[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig  http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# All files\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.sol]\nindent_size = 4\n\n[*.tree]\nindent_size = 1\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "custom: \"https://3cities.xyz/#/pay?c=CAESFAKY9DMuOFdjE4Wzl2YyUFipPiSfIgICATICCAJaFURvbmF0aW9uIHRvIFBhdWwgQmVyZw\"\ngithub: \"PaulRBerg\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug-report.yml",
    "content": "name: \"🐛 Bug report\"\ndescription: \"File a bug report\"\nlabels: [\"bug\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please ensure that the bug has not already been filed in the issue tracker.\n\n        Thanks for taking the time to report this bug!\n  - type: input\n    attributes:\n      description: \"Version tag or commit hash\"\n      label: \"What version of PRBMath are you using?\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"What version of Solidity are you using?\"\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: \"Describe the bug\"\n      description: \"Please include relevant Solidity snippets as well if relevant.\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-feature-request.yml",
    "content": "description: \"Suggest an idea for this project\"\nlabels:\n  - \"feature\"\nname: \"🚀 Feature request\"\nbody:\n  - type: \"textarea\"\n    attributes:\n      label: \"Describe the feature you would like\"\n      description: \"Please also describe what the feature is aiming to solve, if relevant.\"\n    validations:\n      required: true\n  - type: \"textarea\"\n    attributes:\n      label: \"Additional context\"\n      description: \"Add any other context to the feature (like screenshots, resources)\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: \"🙋 Ask a question\"\n    url: \"https://github.com/PaulRBerg/prb-math/discussions/new/choose\"\n    about: \"Ask questions and discuss with other community members\"\n"
  },
  {
    "path": ".github/workflows/ci-multibuild.yml",
    "content": "name: CI Multibuild\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"0 3 * * 0\" # at 3:00am UTC every Sunday\n\njobs:\n  multibuild:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v5\n\n      - name: Install Bun\n        uses: oven-sh/setup-bun@v2\n\n      - name: Install the Node.js dependencies\n        run: bun install\n\n      - name: Check that PRBMath can be built with multiple Solidity versions\n        uses: PaulRBerg/foundry-multibuild@v1\n        with:\n          min: \"0.8.19\"\n          max: \"0.8.30\"\n          skip-test: \"true\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\nconcurrency:\n  cancel-in-progress: true\n  group: ${{github.workflow}}-${{github.ref}}\n\nenv:\n  FOUNDRY_PROFILE: ci\n\non:\n  workflow_dispatch:\n  pull_request:\n  push:\n    branches:\n      - main\n      - staging\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v5\n\n      - name: Install Foundry\n        uses: foundry-rs/foundry-toolchain@v1\n\n      - name: Install Bun\n        uses: oven-sh/setup-bun@v2\n\n      - name: Install the Node.js dependencies\n        run: bun install\n\n      - name: Install Just\n        uses: extractions/setup-just@v3\n\n      - name: Run the full checks\n        run: just full-check\n\n      - name: Add check summary\n        run: | # shell\n          echo \"## Check result\" >> $GITHUB_STEP_SUMMARY\n          echo \"✅ Passed\" >> $GITHUB_STEP_SUMMARY\n\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v5\n\n      - name: Install Bun\n        uses: oven-sh/setup-bun@v2\n\n      - name: Install the Node.js dependencies\n        run: bun install\n\n      - name: Install Foundry\n        uses: foundry-rs/foundry-toolchain@v1\n\n      - name: Build the Solidity code\n        run: forge build\n\n      - name: Add build summary\n        run: | # shell\n          echo \"## Build result\" >> $GITHUB_STEP_SUMMARY\n          echo \"✅ Passed\" >> $GITHUB_STEP_SUMMARY\n\n  test:\n    needs: [check, build]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v5\n\n      - name: Install Foundry\n        uses: foundry-rs/foundry-toolchain@v1\n\n      - name: Install Bun\n        uses: oven-sh/setup-bun@v2\n\n      - name: Install the Node.js dependencies\n        run: bun install\n\n      - name: Run the tests\n        run: forge test --summary\n\n      - name: Add test summary\n        run: | # shell\n          echo \"## Tests result\" >> $GITHUB_STEP_SUMMARY\n          echo \"✅ Passed\" >> $GITHUB_STEP_SUMMARY\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "# Creates GitHub releases automatically when version tags (e.g. v1.0.0) are pushed.\n# Also syncs version branches (e.g. v4.2.0 -> v4 and release-v4).\nname: Release\n\non:\n  push:\n    tags:\n      - \"v[0-9]+.[0-9]+.[0-9]+\"\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v5\n\n      - name: Create Github release\n        uses: docker://antonyurchenko/git-release:v5\n        env:\n          GITHUB_TOKEN: ${{ github.token }}\n\n      - name: Sync version branches with release tag\n        run: | #shell\n          # Extract major version from tag (e.g., v4.2.0 -> v4)\n          TAG_NAME=\"${{ github.ref_name }}\"\n          MAJOR_VERSION=$(echo \"$TAG_NAME\" | cut -d. -f1)\n\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n\n          # Sync both branch patterns: v4 and release-v4\n          for BRANCH in \"$MAJOR_VERSION\" \"release-$MAJOR_VERSION\"; do\n            echo \"Syncing branch '$BRANCH' with tag '$TAG_NAME'\"\n            git fetch origin \"$BRANCH\" || true\n            git checkout -B \"$BRANCH\"\n            git push origin \"$BRANCH\" --force\n          done\n"
  },
  {
    "path": ".gitignore",
    "content": "# directories\ncache\nnode_modules\nout\n\n# files\n*.env\n*.log\n.DS_Store\n.pnp.*\npackage-lock.json\npnpm-lock.yaml\nyarn.lock\n"
  },
  {
    "path": ".prettierignore",
    "content": "# directories\ncache\nnode_modules\nout\n\n# files\n.pnp.*\npackage-lock.json\npnpm-lock.yaml\n"
  },
  {
    "path": ".prettierrc.yml",
    "content": "printWidth: 120\ntrailingComma: \"all\"\n\noverrides:\n  - files: \"*.md\"\n    options:\n      printWidth: 150\n      proseWrap: \"always\"\n"
  },
  {
    "path": ".solhint.json",
    "content": "{\n  \"extends\": \"solhint:recommended\",\n  \"rules\": {\n    \"compiler-version\": [\"error\", \">=0.8.19\"],\n    \"function-max-lines\": \"off\",\n    \"gas-strict-inequalities\": \"off\",\n    \"max-line-length\": [\"error\", 132],\n    \"no-global-import\": \"off\",\n    \"no-inline-assembly\": \"off\",\n    \"use-natspec\": \"off\",\n    \"var-name-mixedcase\": \"off\"\n  }\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"solidity.formatter\": \"forge\",\n  \"[json][jsonc][yaml]\": { \"editor.defaultFormatter\": \"esbenp.prettier-vscode\" },\n  \"[solidity]\": { \"editor.defaultFormatter\": \"NomicFoundation.hardhat-solidity\" },\n  \"[toml]\": { \"editor.defaultFormatter\": \"tamasfe.even-better-toml\" }\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Common Changelog](https://common-changelog.org/), and this project adheres to\n[Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n[4.1.1]: https://github.com/PaulRBerg/prb-math/compare/v4.1.0...v4.1.1\n[4.1.0]: https://github.com/PaulRBerg/prb-math/compare/v4.0.3...v4.1.0\n[4.0.3]: https://github.com/PaulRBerg/prb-math/compare/v4.0.2...v4.0.3\n[4.0.2]: https://github.com/PaulRBerg/prb-math/compare/v4.0.1...v4.0.2\n[4.0.1]: https://github.com/PaulRBerg/prb-math/compare/v4.0.0...v4.0.1\n[4.0.0]: https://github.com/PaulRBerg/prb-math/compare/v3.3.2...v4.0.0\n[3.3.2]: https://github.com/PaulRBerg/prb-math/compare/v3.3.1...v3.3.2\n[3.3.1]: https://github.com/PaulRBerg/prb-math/compare/v3.3.0...v3.3.1\n[3.3.0]: https://github.com/PaulRBerg/prb-math/compare/v3.2.0...v3.3.0\n[3.2.0]: https://github.com/PaulRBerg/prb-math/compare/v3.1.0...v3.2.0\n[3.1.0]: https://github.com/PaulRBerg/prb-math/compare/v3.0.0...v3.1.0\n[3.0.0]: https://github.com/PaulRBerg/prb-math/compare/v2.5.0...v3.0.0\n[2.5.0]: https://github.com/PaulRBerg/prb-math/compare/v2.4.3...v2.5.0\n[2.4.3]: https://github.com/PaulRBerg/prb-math/compare/v2.4.2...v2.4.3\n[2.4.2]: https://github.com/PaulRBerg/prb-math/compare/v2.4.1...v2.4.2\n[2.4.1]: https://github.com/PaulRBerg/prb-math/compare/v2.4.0...v2.4.1\n[2.4.0]: https://github.com/PaulRBerg/prb-math/compare/v2.3.0...v2.4.0\n[2.3.0]: https://github.com/PaulRBerg/prb-math/compare/v2.2.0...v2.3.0\n[2.2.0]: https://github.com/PaulRBerg/prb-math/compare/v2.1.0...v2.2.0\n[2.1.0]: https://github.com/PaulRBerg/prb-math/compare/v2.0.1...v2.1.0\n[2.0.1]: https://github.com/PaulRBerg/prb-math/compare/v2.0.0...v2.0.1\n[2.0.0]: https://github.com/PaulRBerg/prb-math/compare/v1.1.0...v2.0.0\n[1.1.0]: https://github.com/PaulRBerg/prb-math/compare/v1.0.5...v1.1.0\n[1.0.5]: https://github.com/PaulRBerg/prb-math/compare/v1.0.4...v1.0.5\n[1.0.4]: https://github.com/PaulRBerg/prb-math/compare/v1.0.3...v1.0.4\n[1.0.3]: https://github.com/PaulRBerg/prb-math/compare/v1.0.2...v1.0.3\n[1.0.2]: https://github.com/PaulRBerg/prb-math/compare/v1.0.1...v1.0.2\n[1.0.1]: https://github.com/PaulRBerg/prb-math/compare/v1.0.0...v1.0.1\n[1.0.0]: https://github.com/PaulRBerg/prb-math/releases/tag/v1.0.0\n\n## [4.1.1] - 2026-02-11\n\n### Changed\n\n- Rename `DOUBLE_UNIT` local variable to `doubleUnit` in `SD59x18.log2` and `UD60x18.log2` ([#261](https://github.com/PaulRBerg/prb-math/pull/261))\n- Add LaTeX property specifications for `msb` and `sqrt` in `Common.sol` ([#267](https://github.com/PaulRBerg/prb-math/pull/267))\n\n### Fixed\n\n- Fix typos and grammar errors in NatSpec comments ([#270](https://github.com/PaulRBerg/prb-math/pull/270),\n  [#271](https://github.com/PaulRBerg/prb-math/pull/271), [#275](https://github.com/PaulRBerg/prb-math/pull/275))\n\n## [4.1.0] - 2024-10-21\n\n### Changed\n\n- Make domain bound specs more visually descriptive ([#239](https://github.com/PaulRBerg/prb-math/pull/239)) (@PaulRBerg)\n- Update requirement spec in `UD60x18.log2` ([#239](https://github.com/PaulRBerg/prb-math/pull/239)) (@PaulRBerg)\n- Use return instead of param for return parameter NatSpec documentation ([#241](https://github.com/PaulRBerg/prb-math/pull/241)) (@ericglau)\n\n### Added\n\n- Add UD21x18 and SD21x18 types ([#212](https://github.com/PaulRBerg/prb-math/pull/212)) (@andreivladbrg, @PaulRBerg)\n\n### Removed\n\n- Remove adjacent castings ([#237](https://github.com/PaulRBerg/prb-math/pull/237)) (@PaulRBerg)\n\n## [4.0.3] - 2024-06-14\n\n### Changed\n\n- Change visibility of `bound` ([#216](https://github.com/PaulRBerg/prb-math/pull/216)) (@PaulRBerg)\n- Switch to Bun for dependency management ([#218](https://github.com/PaulRBerg/prb-math/pull/218)) (@PaulRBerg)\n\n### Removed\n\n- Remove dependency on `prb-test` ([#222](https://github.com/PaulRBerg/prb-math/pull/222)) (@smol-ninja)\n\n### Fixed\n\n- Fix types for `uUNIT` ([970aa90](https://github.com/PaulRBerg/prb-math/commit/970aa902098af46191d3b38f94bd30e7496078ae)) (@PaulRBerg)\n- Return zero for very small inputs passed to `exp` ([#229](https://github.com/PaulRBerg/prb-math/pull/229)) (@0x2me)\n\n## [4.0.2] - 2023-12-04\n\n### Changed\n\n- Enable `cbor_metadata` by removing the setting ([abdf0b](https://github.com/PaulRBerg/prb-math/commit/abdf0b28909fb2fb149c56cf841ef4d94f916e1e))\n  (@PaulRBerg)\n- Install `prb-test` and `forge-std` as Node.js packages ([#211](https://github.com/PaulRBerg/prb-math/pull/211)) (@andreivladbrg, @PaulRBerg)\n- Update import paths to include `src` ([#210](https://github.com/PaulRBerg/prb-math/pull/210)) (@PaulRBerg)\n- Update NatSpec for `UD60x18.avg` function ([#213](https://github.com/PaulRBerg/prb-math/pull/213)) (@ericglau)\n- Update NatSpec for `PRBMath_SD59x18_Powu_Overflow` custom error ([#194](https://github.com/PaulRBerg/prb-math/pull/194)) (@DaniPopes)\n- Make Node.js the default installation option (@PaulRBerg)\n\n### Added\n\n- Include `test/utils` in Node.js package ([#211](https://github.com/PaulRBerg/prb-math/pull/211)) (@andreivladbrg, @PaulRBerg)\n\n### Removed\n\n- Remove git submodules ([#211](https://github.com/PaulRBerg/prb-math/pull/211)) (@andreivladbrg, @PaulRBerg)\n- Remove the dummy re-exports in `src/test` ([#211](https://github.com/PaulRBerg/prb-math/pull/211)) (@andreivladbrg)\n\n## [4.0.1] - 2023-05-28\n\n### Changed\n\n- Bump submodules (@PaulRBerg)\n- Clarify rounding modes (@PaulRBerg)\n- Move test utils from `src/test` to `test/utils` (@PaulRBerg)\n- Improve documentation (@PaulRBerg)\n\n### Added\n\n- Provide silent `bound` utils (@PaulRBerg)\n\n## [4.0.0] - 2023-04-13\n\n### Changed\n\n- **Breaking**: Rename `fromSD590x18`, `fromUD60x18`, `toSD59x18`, and `toUD60x18` to `convert` (@PaulRBerg)\n- **Breaking**: Rename `Core.sol` to `Common.sol` (@PaulRBerg)\n- **Breaking:** Set minimum compiler pragma to `>=0.8.19` (@PaulRBerg)\n- Bump Node.js dependencies (@PaulRBerg)\n- Bump submodules (@PaulRBerg)\n- Clarify rounding modes ([6bb53ea](https://github.com/PaulRBerg/prb-math/tree/6bb53ea)) (@PaulRBerg)\n- Clarify that `mulDiv` rounds toward zero ([cda291](https://github.com/PaulRBerg/prb-math/tree/cda291)) (@PaulRBerg)\n- Fix typo in code snippet in README ([#180](https://github.com/PaulRBerg/prb-math/pull/180)) (@cygaar)\n- Format contracts with Forge Formatter (@PaulRBerg)\n- Improve writing and formatting in documentation (@PaulRBerg)\n- Make a distinction between `lpotdod` and its flipped counterpart in `Common.mulDiv` (@PaulRBerg)\n- Open pragma in test assertions and utils (@PaulRBerg)\n- Reorder statements in `Common.mulDiv18` (@PaulRBerg)\n- Rename `Common.prbExp2` to `Common.exp2` (@PaulRBerg)\n- Rename `Common.prbSqrt` to `Common.sqrt` (@PaulRBerg)\n- Rename `Assertions` to `PRBMathAssertions` (@PaulRBerg)\n- Return base when exponent is unit in `pow` ([#182](https://github.com/PaulRBerg/prb-math/pull/182)) (@PaulRBerg)\n- Return unit when base is unit in `pow` ([#182](https://github.com/PaulRBerg/prb-math/pull/182)) (@PaulRBerg)\n- Switch to Pnpm for Node.js package management (@PaulRBerg)\n- Use bound `unwrap` instead of imported `unwrap` (@PaulRBerg)\n- Use long names in named imports (@PaulRBerg)\n\n### Added\n\n- Add `EXP_MAX_INPUT` and `EXP2_MAX_INPUT` constants, and use them in `exp` and `exp2` (@PaulRBerg)\n- Add `UNIT_SQUARED` and use it instead of the hard-coded value (@PaulRBerg)\n- Add user-defined operators ([#168](https://github.com/PaulRBerg/prb-math/pull/168)) (@Amxx,@PaulRBerg)\n- Add unary operator ([#173](https://github.com/PaulRBerg/prb-math/pull/173)) (@Lumyo,@PaulRBerg)\n- Expand domain of `pow` in `UD60x18` by allowing inputs lower than `UNIT` ([#182](https://github.com/PaulRBerg/prb-math/pull/182)) (@PaulRBerg)\n\n### Removed\n\n- Remove development-related Node.js dependencies (@PaulRBerg)\n- Remove \"memory-safe\" annotation in test assertions (@PaulRBerg)\n- Remove problematic src/=src/ remapping (#41) (@PaulRBerg)\n- Remove superfluous threshold check in `SD59x19.exp` (@PaulRBerg)\n\n### Fixed\n\n- Fix bit mask in `Common.exp2` ([#179](https://github.com/PaulRBerg/prb-math/pull/179)) (@andreivladbrg)\n\n## [3.3.2] - 2023-03-19\n\n### Changed\n\n- Use `ValueType.wrap` directly in casting functions (@PaulRBerg)\n\n## [3.3.1] - 2023-03-17\n\n### Changed\n\n- Bump submodules (@PaulRBerg)\n\n## [3.3.0] - 2023-02-06\n\n### Changed\n\n- Improve documentation (@PaulRBerg)\n- Improve names of custom errors and functions (@PaulRBerg)\n- Optimize assembly usage by annotating assembly blocks with the \"memory-safe\" dialect (@PaulRBerg)\n- Modularize code by splitting it into multiple categories: casting, constants, conversions, errors, helpers, math, and value types (@PaulRBerg)\n- Rename `Assertions` to `PRBMathAssertions` in a backward-compatible way (@PaulRBerg)\n- Upgrade Node.js package dependencies (@PaulRBerg)\n\n### Added\n\n- Add casting utilities for PRBMath types and `uint128` and `uint40` (@PaulRBerg)\n- Add more constants in `SD1x18` and `UD2x18` (@PaulRBerg)\n- Add `PRBMathUtils` contract with test utils (@PaulRBerg)\n- Add test assertions overloads with `err` param (@PaulRBerg)\n- Add typed versions of `bound` test util (@PaulRBerg)\n- Add `wrap` and `unwrap` in `SD1x18` and `UD2x18` (@PaulRBerg)\n- Expose `unwrap` via `using for ... global` (@PaulRBerg)\n\n## [3.2.0] - 2022-12-13\n\n### Added\n\n- Add assertions for array comparisons (@PaulRBerg)\n\n### Removed\n\n- Delete assertions that have an \"err\" argument (@PaulRBerg)\n\n### Fixed\n\n- Match types for `SD1x18` and `UD2x18` assertions (@PaulRBerg)\n\n## [3.1.0] - 2022-12-13\n\n### Added\n\n- Add value types `SD1x18` and `UD2x18` (@PaulRBerg)\n\n## [3.0.0] - 2022-11-29\n\n[1b82ea]: https://github.com/PaulRBerg/prb-math/commit/1b82ea\n[a69b4b]: https://github.com/PaulRBerg/prb-math/commit/a69b4b\n\n### Changed\n\n- **Breaking:** Refactor the libraries into free functions and user defined value types ([`a69b4b`][a69b4b]) (@PaulRBerg)\n- **Breaking:** Set minimum compiler pragma to `>=0.8.13` ([`a69b4b`][a69b4b]) (@PaulRBerg)\n- **Breaking:** Rename `SCALE` to `UNIT` ([`4d3658`](https://github.com/PaulRBerg/prb-math/commit/4d3658)) (@PaulRBerg)\n- Always truncate instead of rounding up in multiplication functions ([21fb32](https://github.com/PaulRBerg/prb-math/commit/21fb32)) (@PaulRBerg)\n- Change license to MIT (@PaulRBerg)\n- Check if `y` is zero in `gm` ([`5b585c`](https://github.com/PaulRBerg/prb-math/commit/5b585c)) (@PaulRBerg)\n- Optimize `avg` by using the SWAR technique ([#89](https://github.com/PaulRBerg/prb-math/pull/89)) (@PaulRBerg)\n- Optimize `div` and `mulDivSigned` by wrapping unary operations in unchecked blocks ([`a69b4b`][a69b4b]) (@PaulRBerg)\n- Optimize `exp2` by batching bit checks ([#77](https://github.com/PaulRBerg/prb-math/pull/77)) (@k06a)\n- Optimize `msb` by using assembly ([#135](https://github.com/PaulRBerg/prb-math/pull/135)) (@t4sk, @PaulRBerg)\n- Optimize result assignment in `powu` ([673802](https://github.com/PaulRBerg/prb-math/commit/673802)) (@PaulRBerg)\n- Rename `fromInt` to `toSD59x18` and `toInt` to `fromSD59x18` ([`a69b4b`][a69b4b]) (@PaulRBerg)\n- Rename `fromUint` to `toUD60x18` and `toUint` to `fromUD60x18` ([`a69b4b`][a69b4b]) (@PaulRBerg)\n- Rename `mostSignificantBit` to `msb` ([`a69b4b`][a69b4b]) (@PaulRBerg)\n- Rename `mulDivFixedPoint` to `mulDiv18` ([`4c5430`](https://github.com/PaulRBerg/prb-math/commit/4c5430)) (@PaulRBerg)\n- Rename `PRBMath.sol` to `Core.sol` ([`1b82ea`][1b82ea]) (@PaulRBerg)\n- Rename shared `sqrt` in `prbSqrt` ([`1b82ea`][1b82ea]) (@PaulRBerg)\n- Rename shared `exp2` in `prbExp2` ([`1b82ea`][1b82ea]) (@PaulRBerg)\n- Revert with inputs instead of computed value custom errors (@PaulRBerg)\n- Return base if exponent is one in `pow` ([`977d43`](https://github.com/PaulRBerg/prb-math/commit/977d43)) (@PaulRBerg)\n- Format mathematical expressions using LaTeX (@PaulRBerg)\n- Improve wording and formatting in comments, NatSpec documentation, and README (@PaulRBerg)\n\n### Added\n\n- Add constants for E and PI ([`422d87`](https://github.com/PaulRBerg/prb-math/commit/422d87)) (@PaulRBerg)\n- Add simple PRBTest-based typed assertions for testing in Foundry ([`ddb084`](https://github.com/PaulRBerg/prb-math/commit/ddb084)) (@PaulRBerg)\n- Add user defined value types `SD59x18` and `UD60x18` (@PaulRBerg)\n- Implement conversion and helper functions for the user defined value types (@PaulRBerg)\n\n### Removed\n\n- **Breaking:** Delete the `e` and `pi` functions ([422d87](https://github.com/PaulRBerg/prb-math/commit/422d87)) (@PaulRBerg)\n- **Breaking:** Remove JavaScript SDK and all paraphernalia ([`1b82ea`][1b82ea]) (@PaulRBerg)\n\n### Fixed\n\n- Fix incorrect hard-coded value in `sqrt` ([#91](https://github.com/PaulRBerg/prb-math/pull/91)) (@Amxx, @nonergodic)\n- Fix upper boundary specified in `exp` NatSpec comments ([#119](https://github.com/PaulRBerg/prb-math/discussions/119)) (@PaulRBerg)\n\n## [2.5.0] - 2022-03-08\n\n### Changed\n\n- Change the package name from `prb-math` to `@prb/math` (@PaulRBerg)\n- Update links to repository (@PaulRBerg)\n- Upgrade to `mathjs` v10.4.0 (@PaulRBerg)\n\n## [2.4.3] - 2022-02-02\n\n### Fixed\n\n- Peer dependency version for `mathjs` (@PaulRBerg)\n\n## [2.4.2] - 2022-02-02\n\n### Changed\n\n- Upgrade to `mathjs` v10.1.1 (@PaulRBerg)\n\n### Fixed\n\n- Fix typo in comment in `sqrt` ([#67](https://github.com/PaulRBerg/prb-math/pull/67) (@transmissions11)\n\n## [2.4.1] - 2021-10-27\n\n### Changed\n\n- Upgrade to `@ethersproject/bignumber` v5.5.0 (@PaulRBerg)\n\n### Fixed\n\n- Set peer dependencies (@PaulRBerg)\n\n## [2.4.0] - 2021-10-20\n\n### Added\n\n- `@ethersproject/bignumber`, `decimal.js`, `evm-bn`, and `mathjs` as normal deps (@PaulRBerg)\n- Ship JavaScript source maps with the npm package (@PaulRBerg)\n\n### Changed\n\n- Americanize spellings in NatSpec comments (@PaulRBerg)\n- Move everything from the `prb-math.js` package to `prb-math` (@PaulRBerg)\n- Polish NatSpec comments in `avg` function (@PaulRBerg)\n- Use underscores in number literals (@PaulRBerg)\n\n### Fixed\n\n- Fix bug in the `powu` function of the `PRBMathSD59x18` contract, which caused the result to be positive even if the base was negative (@PaulRBerg)\n- Fix minor bug in the `avg` function of the `PRBMathSD59x18` contract, which rounded down the result instead of up when the intermediary sum was\n  negative (@PaulRBerg)\n\n## [2.3.0] - 2021-09-18\n\n### Added\n\n- The CHANGELOG file in the npm package bundle (@PaulRBerg)\n\n### Changed\n\n- License from \"WTFPL\" to \"Unlicense\" (@PaulRBerg)\n- Polish README (@PaulRBerg)\n\n### Fixed\n\n- Typos in comments (@PaulRBerg)\n\n### Removed\n\n- Remove stale \"resolutions\" field in `package.json` (@PaulRBerg)\n\n## [2.2.0] - 2021-06-27\n\n### Changed\n\n- Add contract name prefix to custom errors (@PaulRBerg)\n\n### Removed\n\n- Remove `@param` tags in custom errors' NatSpec (@PaulRBerg)\n\n## [2.1.0] - 2021-06-27\n\n### Changed\n\n- Define the upper limit as `MAX_UD60x18 / SCALE` in the `sqrt` function (@PaulRBerg)\n- Define `xValue` var to avoid reading `x.value` multiple times (@PaulRBerg)\n- Move `SCALE > prod1` check at the top of the `mulDivFixedPoint` function (@PaulRBerg)\n- Refer to `add` function operands as summands (@PaulRBerg)\n- Refer to `sub` function operands as minuend and subtrahend (@PaulRBerg)\n- Rename `rUnsigned` var to `rAbs` (@PaulRBerg)\n- Set minimum compiler pragma to `>=0.8.4` (@PaulRBerg)\n- Use `MIN_SD59x18` instead of `type(int256).min` where appropriate (@PaulRBerg)\n\n### Added\n\n- Add Solidity v0.8.4 custom errors (@PaulRBerg)\n\n### Removed\n\n- Remove stale `hardhat/console.sol` import (@PaulRBerg)\n- Remove stale caveat in the NatSpec for `sqrt` (@PaulRBerg)\n\n## [2.0.1] - 2021-06-16\n\n### Changed\n\n- Mention the new typed flavors in the README (@PaulRBerg)\n\n### Fixed\n\n- Code snippet for the UD60x18Typed consumer in the README (@PaulRBerg)\n- English typos in NatSpec comments ([#40](https://github.com/PaulRBerg/prb-math/pull/40)) (@ggviana)\n- Minor bug in `log10` in `PRBMathUD60x18Typed.sol` which made the result inaccurate when the input was a multiple of 10 (@PaulRBerg)\n\n## [2.0.0] - 2021-06-14\n\n### Changed\n\n- **Breaking**: Rename `PRBMathCommon.sol` to `PRBMath.sol` (@PaulRBerg)\n- Increase the accuracy of `exp2` by using the 192.64-bit format instead of 128.128-bit (@PaulRBerg)\n- Set named parameter instead of returning result in `pow` functions (@PaulRBerg)\n- Update gas estimates for `exp` and `exp2` (@PaulRBerg)\n\n### Added\n\n- Add `add` and `sub` functions in the typed libraries (@PaulRBerg)\n- Add types flavors of the library: `PRBMathSD59x18Typed.sol` and `PRBMathUD60x18Typed.sol` (@PaulRBerg)\n- Document gas estimates for `fromInt`, `fromUint`, `pow`, `toInt` and `toUInt` (@PaulRBerg)\n- Structs `PRBMath.SD59x18` and `PRBMath.UD60x18`, simple wrappers to indicate that the variables are fixed-point numbers (@PaulRBerg)\n\n### Fixed\n\n- Bug in `log10` which made the result incorrect when the input was not a multiple of 10 (@PaulRBerg)\n- Typos in NatSpec comments (@PaulRBerg)\n\n## [1.1.0] - 2021-05-07\n\n_This release was yanked because it was accidentally published with the wrong version number._\n\n### Changed\n\n- Rename the previous `pow` function to `powu` (@PaulRBerg)\n- Speed up `exp2` by simplifying the integer part calculations (@PaulRBerg)\n- Use the fixed-point format in NatSpec comments (@PaulRBerg)\n\n### Added\n\n- Add new converter functions `fromInt` and `toInt` in `PRBMathSD59x18.sol` (@PaulRBerg)\n- Add new converter functions `fromUint` and `toUint` in `PRBMathUD60x18.sol` (@PaulRBerg)\n- Add new function `mulDivSigned` in `PRBMathCommon.sol` (@PaulRBerg)\n- Add new function `pow` in `PRBMathSD59x18.sol` and `PRBMathUD60x18.sol` (@PaulRBerg)\n\n### Fixed\n\n- Fix minor typos in NatSpec comments (@PaulRBerg)\n\n## [1.0.5] - 2021-04-24\n\n### Changed\n\n- Speed up the `exp2` function in PRBMathCommon.sol by simplifying the integer part calculation (@PaulRBerg))\n- Use `SCALE` instead of the 1e18 literal in `PRBMathCommon.sol` (@PaulRBerg)\n\n### Added\n\n- Add link to StackExchange answer in `exp2` NatSpec comments (@PaulRBerg)\n\n## [1.0.4] - 2021-04-20\n\n### Changed\n\n- Optimize the `pow` function in `PRBMathUD60x18` by calling `mulDivFixedPoint` directly (@PaulRBerg)\n\n## [1.0.3] - 2021-04-20\n\n### Fixed\n\n- Fix typos in NatSpec comments (@PaulRBerg)\n- Fix typo in example in README (@PaulRBerg)\n\n### Removed\n\n- Remove `SCALE_LPOTD` and `SCALE_INVERSE` constants in `PRBMathSD59x18` (@PaulRBerg)\n\n## [1.0.2] - 2021-04-19\n\n### Removed\n\n- Remove stale `SCALE_LPOTD` and `SCALE_INVERSE` constants in `PRBMathUD60x18` (@PaulRBerg)\n\n## [1.0.1] - 2021-04-19\n\n### Changed\n\n- Change in the README (@PaulRBerg)\n\n## [1.0.0] - 2021-04-19\n\n### Added\n\n- First release of the library (@PaulRBerg)\n"
  },
  {
    "path": "CLAUDE.md",
    "content": "# PRBMath\n\nSolidity library for advanced fixed-point math with signed (SD59x18) and unsigned (UD60x18) 18-decimal types.\n\n## Stack\n\n- Solidity 0.8.30\n- Foundry (forge build, forge test, forge fmt)\n- Bun for package management\n- Prettier, Solhint for formatting/linting\n\n## Structure\n\n```\nsrc/\n  Common.sol          # Shared utilities (mulDiv, exp2, log2, pow, sqrt)\n  SD59x18.sol         # Signed 59.18 fixed-point type\n  UD60x18.sol         # Unsigned 60.18 fixed-point type\n  SD1x18.sol          # Signed 1.18 (compact)\n  UD2x18.sol          # Unsigned 2.18 (compact)\n  SD21x18.sol         # Signed 21.18 (medium)\n  UD21x18.sol         # Unsigned 21.18 (medium)\n  sd59x18/            # SD59x18 operations (math, conversions, helpers)\n  ud60x18/            # UD60x18 operations (math, conversions, helpers)\n  casting/            # Type casting between formats\ntest/\n  unit/               # Unit tests\n  fuzz/               # Fuzz tests\n  utils/              # Test utilities\n```\n\n## Commands\n\n- `bun run build` - Build with Forge\n- `bun run test` - Run tests (`forge test`)\n- `bun run full-check` - Prettier + Solhint + Forge format check\n- `bun run full-write` - Auto-fix all formatting issues\n\n## Development\n\nAfter generating or updating code:\n\n1. Run `bun run full-check` to verify\n2. If errors, run `bun run full-write` to auto-fix\n3. Fix remaining issues manually\n\nInstall dependencies: `bun install` or `bun install -d <pkg>` for dev deps.\n\n## Code Style\n\n- Use user-defined value types (SD59x18, UD60x18) for type safety\n- Free functions over library pattern\n- Custom errors over require strings\n- NatSpec comments on public functions\n- Line length: 132 chars\n- 4-space tabs\n- Bracket spacing enabled\n\n## Fixed-Point Formats\n\n| Type    | Signed | Integer Digits | Decimals |\n| ------- | ------ | -------------- | -------- |\n| SD59x18 | Yes    | 59             | 18       |\n| UD60x18 | No     | 60             | 18       |\n| SD1x18  | Yes    | 1              | 18       |\n| UD2x18  | No     | 2              | 18       |\n| SD21x18 | Yes    | 21             | 18       |\n| UD21x18 | No     | 21             | 18       |\n\n## Testing\n\n```bash\nforge test                           # Run all tests\nforge test --match-test testFoo      # Run specific test\nforge test --match-contract Exp2     # Run tests in contract\nFOUNDRY_PROFILE=ci forge test        # CI profile with more fuzz runs\n```\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2023-present Paul Razvan Berg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# PRBMath [![GitHub Actions][gha-badge]][gha] [![Foundry][foundry-badge]][foundry] [![License: MIT][license-badge]][license]\n\n[gha]: https://github.com/PaulRBerg/prb-math/actions\n[gha-badge]: https://github.com/PaulRBerg/prb-math/actions/workflows/ci.yml/badge.svg\n[foundry]: https://getfoundry.sh/\n[foundry-badge]: https://img.shields.io/badge/Built%20with-Foundry-FFDB1C.svg\n[license]: https://opensource.org/licenses/MIT\n[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg\n\n<div align=\"center\">\n  <img src=\"./assets/logo.png\" alt=\"PRBMath Logo\" width=\"250\">\n</div>\n\n**Solidity library for advanced fixed-point math** that operates with signed 59.18-decimal fixed-point and unsigned 60.18-decimal fixed-point numbers.\nThe name of the number format comes from the integer part having up to 59 digits for signed numbers and 60 digits for unsigned numbers, while the\nfractional part has up to 18 decimals. The numbers are bound by the minimum and the maximum values permitted by the Solidity types int256 and uint256.\n\n- Operates with signed and unsigned denary fixed-point numbers, with 18 trailing decimals\n- Offers advanced math functions like logarithms, exponentials, powers and square roots\n- Provides type safety via user-defined value types\n- Gas efficient, but still user-friendly\n- Ergonomic developer experience thanks to using free functions instead of libraries\n- Bakes in overflow-safe multiplication and division via `mulDiv`\n- Reverts with custom errors instead of reason strings\n- Well-documented with NatSpec comments\n- Built and tested with Foundry\n\n> [!NOTE]\n>\n> PRBMath is a fixed-point math library that is at the same time intuitive, efficient and safe.\n> [ABDKMath64x64](https://github.com/abdk-consulting/abdk-libraries-solidity) is fast, but uses binary numbers, which are counter-intuitive.\n> [Solmate](https://github.com/transmissions11/solmate) is fast and intuitive, but lacks type safety.\n\n## 📦 Install\n\n### 🟢 Node.js\n\nThis is the recommended approach.\n\nInstall PRBMath using your favorite package manager, e.g., with Bun:\n\n```shell\nbun add @prb/math\n```\n\nThen, if you are using Foundry, you need to add this to your `remappings.txt` file:\n\n```text\n@prb/math/=node_modules/@prb/math/\n```\n\n### 🔗 Git Submodules\n\nThis installation method is not recommended, but it is available for those who prefer it.\n\nFirst, install the submodule using Forge:\n\n```shell\nforge install  PaulRBerg/prb-math@release-v4\n```\n\nYour `.gitmodules` file should now contain the following entry:\n\n```toml\n[submodule \"lib/prb-math\"]\n  branch = \"release-v4\"\n  path = \"lib/prb-math\"\n  url = \"https://github.com/PaulRBerg/prb-math\"\n```\n\nFinally, add this to your `remappings.txt` file:\n\n```text\n@prb/math/=lib/prb-math/\n```\n\n## 🚀 Usage\n\nThere are two user-defined value types:\n\n1. SD59x18 (signed)\n2. UD60x18 (unsigned)\n\nIf you don't know what a user-defined value type is, check out this [blog post](https://blog.soliditylang.org/2021/09/27/user-defined-value-types/).\n\nIf you don't need negative numbers, there's no point in using the signed flavor `SD59x18`. The unsigned flavor `UD60x18` is more gas efficient.\n\nNote that PRBMath is not a library in the Solidity [sense](https://docs.soliditylang.org/en/v0.8.17/contracts.html#libraries). It's just a collection\nof free functions.\n\n### 📥 Importing\n\nIt is recommended that you import PRBMath using specific symbols. Importing full files can result in Solidity complaining about duplicate definitions\nand static analyzers like Slither erroring, especially as repos grow and have more dependencies with overlapping names.\n\n```solidity\npragma solidity >=0.8.19;\n\nimport { SD59x18 } from \"@prb/math/src/SD59x18.sol\";\nimport { UD60x18 } from \"@prb/math/src/UD60x18.sol\";\n```\n\nAny function that is not available in the types directly has to be imported explicitly. Here's an example for the `sd` and the `ud` functions:\n\n```solidity\npragma solidity >=0.8.19;\n\nimport { SD59x18, sd } from \"@prb/math/src/SD59x18.sol\";\nimport { UD60x18, ud } from \"@prb/math/src/UD60x18.sol\";\n```\n\nNote that PRBMath can only be used in Solidity v0.8.19 and above.\n\n### ➕ SD59x18\n\n```solidity\n// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\nimport { SD59x18, sd } from \"@prb/math/src/SD59x18.sol\";\n\ncontract SignedConsumer {\n  /// @notice Calculates 5% of the given signed number.\n  /// @dev Try this with x = 400e18.\n  function signedPercentage(SD59x18 x) external pure returns (SD59x18 result) {\n    SD59x18 fivePercent = sd(0.05e18);\n    result = x.mul(fivePercent);\n  }\n\n  /// @notice Calculates the binary logarithm of the given signed number.\n  /// @dev Try this with x = 128e18.\n  function signedLog2(SD59x18 x) external pure returns (SD59x18 result) {\n    result = x.log2();\n  }\n}\n```\n\n### ➕ UD60x18\n\n```solidity\n// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\nimport { UD60x18, ud } from \"@prb/math/src/UD60x18.sol\";\n\ncontract UnsignedConsumer {\n  /// @notice Calculates 5% of the given unsigned number.\n  /// @dev Try this with x = 400e18.\n  function unsignedPercentage(UD60x18 x) external pure returns (UD60x18 result) {\n    UD60x18 fivePercent = ud(0.05e18);\n    result = x.mul(fivePercent);\n  }\n\n  /// @notice Calculates the binary logarithm of the given unsigned number.\n  /// @dev Try this with x = 128e18.\n  function unsignedLog2(UD60x18 x) external pure returns (UD60x18 result) {\n    result = x.log2();\n  }\n}\n```\n\n## ✨ Features\n\nBecause there's significant overlap between the features available in SD59x18 and UD60x18, there is only one table per section. If in doubt, refer to\nthe source code, which is well-documented with NatSpec comments.\n\n### 🔢 Mathematical Functions\n\n| Name    | Operator | Description                                      |\n| ------- | -------- | ------------------------------------------------ |\n| `abs`   | N/A      | Absolute value                                   |\n| `avg`   | N/A      | Arithmetic average                               |\n| `ceil`  | N/A      | Smallest whole number greater than or equal to x |\n| `div`   | `/`      | Fixed-point division                             |\n| `exp`   | N/A      | Natural exponential e^x                          |\n| `exp2`  | N/A      | Binary exponential 2^x                           |\n| `floor` | N/A      | Greatest whole number less than or equal to x    |\n| `frac`  | N/A      | Fractional part                                  |\n| `gm`    | N/A      | Geometric mean                                   |\n| `inv`   | N/A      | Inverse 1÷x                                      |\n| `ln`    | N/A      | Natural logarithm ln(x)                          |\n| `log10` | N/A      | Common logarithm log10(x)                        |\n| `log2`  | N/A      | Binary logarithm log2(x)                         |\n| `mul`   | `*`      | Fixed-point multiplication                       |\n| `pow`   | N/A      | Power function x^y                               |\n| `powu`  | N/A      | Power function x^y with y simple integer         |\n| `sqrt`  | N/A      | Square root                                      |\n\n### 🔗 Adjacent Value Types\n\nPRBMath provides adjacent value types that serve as abstractions over other vanilla types:\n\n| Value Type | Underlying Type |\n| ---------- | --------------- |\n| `SD1x18`   | int64           |\n| `SD21x18`  | int128          |\n| `UD2x18`   | uint64          |\n| `UD21x18`  | uint128         |\n\nThese are useful if you want to save gas by using a lower bit width integer, e.g., in a struct.\n\nNote that these types don't have any mathematical functionality. To do math with them, you will have to unwrap them into a simple integer and then to\nthe core types `SD59x18` and `UD60x18`.\n\n### 🔄 Casting Functions\n\nAll PRBMath types have casting functions to and from all other types, including a few basic types like `uint128` and `uint40`.\n\n| Name          | Description               |\n| ------------- | ------------------------- |\n| `intoSD1x18`  | Casts a number to SD1x18  |\n| `intoSD59x18` | Casts a number to SD59x18 |\n| `intoUD2x18`  | Casts a number to UD2x18  |\n| `intoUD60x18` | Casts a number to UD60x18 |\n| `intoUint256` | Casts a number to uint256 |\n| `intoUint128` | Casts a number to uint128 |\n| `intoUint40`  | Casts a number to uint40  |\n| `sd1x18`      | Alias for `SD1x18.wrap`   |\n| `sd59x18`     | Alias for `SD59x18.wrap`  |\n| `ud2x18`      | Alias for `UD2x18.wrap`   |\n| `ud60x18`     | Alias for `UD60x18.wrap`  |\n\n### ⚡ Conversion Functions\n\nThe difference between \"conversion\" and \"casting\" is that conversion functions multiply or divide the inputs, whereas casting functions simply cast\nthem.\n\n| Name               | Description                                                           |\n| ------------------ | --------------------------------------------------------------------- |\n| `convert(SD59x18)` | Converts an SD59x18 number to a simple integer by dividing it by 1e18 |\n| `convert(UD60x18)` | Converts a UD60x18 number to a simple integer by dividing it by 1e18  |\n| `convert(int256)`  | Converts a simple integer to SD59x18 by multiplying it by 1e18        |\n| `convert(uint256)` | Converts a simple integer to UD60x18 type by multiplying it by 1e18   |\n\n### 🛠️ Helper Functions\n\nIn addition to offering mathematical, casting, and conversion functions, PRBMath provides numerous helper functions for user-defined value types:\n\n| Name           | Operator | Description               |\n| -------------- | -------- | ------------------------- |\n| `add`          | `+`      | Checked addition          |\n| `and`          | `&`      | Logical AND               |\n| `eq`           | `==`     | Equality                  |\n| `gt`           | `>`      | Greater than operator     |\n| `gte`          | `>=`     | Greater than or equal to  |\n| `isZero`       | N/A      | Check if a number is zero |\n| `lshift`       | N/A      | Bitwise left shift        |\n| `lt`           | `<`      | Less than                 |\n| `lte`          | `<=`     | Less than or equal to     |\n| `mod`          | `%`      | Modulo                    |\n| `neq`          | `!=`     | Not equal operator        |\n| `not`          | `~`      | Negation operator         |\n| `or`           | `\\|`     | Logical OR                |\n| `rshift`       | N/A      | Bitwise right shift       |\n| `sub`          | `-`      | Checked subtraction       |\n| `unary`        | `-`      | Checked unary             |\n| `uncheckedAdd` | N/A      | Unchecked addition        |\n| `uncheckedSub` | N/A      | Unchecked subtraction     |\n| `xor`          | `^`      | Exclusive or (XOR)        |\n\nThese helpers are designed to streamline basic operations such as addition and equality checks, eliminating the need to constantly unwrap and re-wrap\nvariables. However, it is important to be aware that utilizing these functions may result in increased gas costs compared to unwrapping and directly\nusing the vanilla types.\n\n```solidity\n// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\nimport { UD60x18, ud } from \"@prb/math/src/UD60x18.sol\";\n\nfunction addRshiftEq() pure returns (bool result) {\n  UD60x18 x = ud(1e18);\n  UD60x18 y = ud(3e18);\n  y = y.add(x); // also: y = y + x\n  y = y.rshift(2);\n  result = x.eq(y); // also: y == x\n}\n\n```\n\n### ✅ Assertions\n\nPRBMath comes with typed assertions that you can use for writing tests with [PRBTest](https://github.com/PaulRBerg/prb-test), which is based on\nFoundry. This is useful if, for example, you would like to assert that two UD60x18 numbers are equal.\n\n```solidity\npragma solidity >=0.8.19;\n\nimport { UD60x18, ud } from \"@prb/math/src/UD60x18.sol\";\nimport { Assertions as PRBMathAssertions } from \"@prb/math/test/Assertions.sol\";\nimport { PRBTest } from \"@prb/math/src/test/PRBTest.sol\";\n\ncontract MyTest is PRBTest, PRBMathAssertions {\n  function testAdd() external {\n    UD60x18 x = ud(1e18);\n    UD60x18 y = ud(2e18);\n    UD60x18 z = ud(3e18);\n    assertEq(x.add(y), z);\n  }\n}\n```\n\n## ⚡ Gas Efficiency\n\nPRBMath is faster than ABDKMath for `abs`, `exp`, `exp2`, `gm`, `inv`, `ln`, `log2`, but it is slower than ABDKMath for `avg`, `div`, `mul`, `powu`\nand `sqrt`.\n\nThe main reason why PRBMath lags behind ABDKMath's `mul` and `div` functions is that it operates with 256-bit word sizes, and so it has to account for\npossible intermediary overflow. ABDKMath, on the other hand, operates with 128-bit word sizes.\n\n**Note**: I did not find a good way to automatically generate gas reports for PRBMath. See the\n[#134](https://github.com/PaulRBerg/prb-math/discussions/134) discussion for more details about this issue.\n\n### PRBMath\n\nGas estimations based on the [v2.0.1](https://github.com/PaulRBerg/prb-math/releases/tag/v2.0.1) and the\n[v3.0.0](https://github.com/PaulRBerg/prb-math/releases/tag/v3.0.0) releases.\n\n| SD59x18 | Min | Max   | Avg  |     | UD60x18 | Min  | Max   | Avg  |\n| ------- | --- | ----- | ---- | --- | ------- | ---- | ----- | ---- |\n| abs     | 68  | 72    | 70   |     | n/a     | n/a  | n/a   | n/a  |\n| avg     | 95  | 105   | 100  |     | avg     | 57   | 57    | 57   |\n| ceil    | 82  | 117   | 101  |     | ceil    | 78   | 78    | 78   |\n| div     | 431 | 483   | 451  |     | div     | 205  | 205   | 205  |\n| exp     | 38  | 2797  | 2263 |     | exp     | 1874 | 2742  | 2244 |\n| exp2    | 63  | 2678  | 2104 |     | exp2    | 1784 | 2652  | 2156 |\n| floor   | 82  | 117   | 101  |     | floor   | 43   | 43    | 43   |\n| frac    | 23  | 23    | 23   |     | frac    | 23   | 23    | 23   |\n| gm      | 26  | 892   | 690  |     | gm      | 26   | 893   | 691  |\n| inv     | 40  | 40    | 40   |     | inv     | 40   | 40    | 40   |\n| ln      | 463 | 7306  | 4724 |     | ln      | 419  | 6902  | 3814 |\n| log10   | 104 | 9074  | 4337 |     | log10   | 503  | 8695  | 4571 |\n| log2    | 377 | 7241  | 4243 |     | log2    | 330  | 6825  | 3426 |\n| mul     | 455 | 463   | 459  |     | mul     | 219  | 275   | 247  |\n| pow     | 64  | 11338 | 8518 |     | pow     | 64   | 10637 | 6635 |\n| powu    | 293 | 24745 | 5681 |     | powu    | 83   | 24535 | 5471 |\n| sqrt    | 140 | 839   | 716  |     | sqrt    | 114  | 846   | 710  |\n\n### ABDKMath64x64\n\nGas estimations based on the v3.0 release of ABDKMath. See my [abdk-gas-estimations](https://github.com/PaulRBerg/abdk-gas-estimations) repo.\n\n| Method | Min  | Max  | Avg  |\n| ------ | ---- | ---- | ---- |\n| abs    | 88   | 92   | 90   |\n| avg    | 41   | 41   | 41   |\n| div    | 168  | 168  | 168  |\n| exp    | 77   | 3780 | 2687 |\n| exp2   | 77   | 3600 | 2746 |\n| gavg   | 166  | 875  | 719  |\n| inv    | 157  | 157  | 157  |\n| ln     | 7074 | 7164 | 7126 |\n| log2   | 6972 | 7062 | 7024 |\n| mul    | 111  | 111  | 111  |\n| pow    | 303  | 4740 | 1792 |\n| sqrt   | 129  | 809  | 699  |\n\n## 🤝 Contributing\n\nFeel free to dive in! [Open](https://github.com/PaulRBerg/prb-math/issues/new) an issue,\n[start](https://github.com/PaulRBerg/prb-math/discussions/new) a discussion or submit a PR.\n\n### 📋 Pre Requisites\n\nYou will need the following software on your machine:\n\n- [Git](https://git-scm.com/downloads)\n- [Foundry](https://github.com/foundry-rs/foundry)\n- [Node.Js](https://nodejs.org/en/download/)\n- [Bun](https://bun.sh)\n\nIn addition, familiarity with [Solidity](https://soliditylang.org/) is requisite.\n\n### ⚙️ Set Up\n\nClone this repository including submodules:\n\n```sh\n$ git clone --recurse-submodules -j8 git@github.com:PaulRBerg/prb-math.git\n```\n\nThen, inside the project's directory, run this to install the Node.js dependencies:\n\n```sh\n$ bun install\n```\n\nNow you can start making changes.\n\n### 🎨 Syntax Highlighting\n\nYou will need the following VSCode extensions:\n\n- [hardhat-solidity](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity)\n- [vscode-tree-language](https://marketplace.visualstudio.com/items?itemName=CTC.vscode-tree-extension)\n\n## 🔒 Security\n\nThe codebase has undergone audits by leading security experts from Cantina and Certora. For a comprehensive list of all audits conducted, see the\n[SECURITY](./SECURITY.md) file.\n\n### ⚠️ Caveat Emptor\n\nThis is experimental software and is provided on an \"as is\" and \"as available\" basis. I do not give any warranties and will not be liable for any\nloss, direct or indirect through continued use of this codebase.\n\n### 📞 Contact\n\nIf you discover any bugs or security issues, please report them via [Telegram](https://t.me/PaulRBerg).\n\n## 🙏 Acknowledgments\n\n- Mikhail Vladimirov for the insights he shared in the [Math in Solidity](https://medium.com/coinmonks/math-in-solidity-part-1-numbers-384c8377f26d)\n  article series.\n- Remco Bloemen for his work on [overflow-safe multiplication and division](https://xn--2-umb.com/21/muldiv/), and for responding to the questions I\n  asked him while developing the library.\n- Everyone who has contributed a PR to this repository.\n\n<h2>\n  <img src=\"./assets/op.png\"\n       alt=\"Optimism logo\"\n       width=\"23\" />\n  Retro Funding\n</h2>\n\nA big shoutout and thank you to the [Optimism](https://optimism.io) team for funding the development of this library via the\n[Retro Funding](https://atlas.optimism.io/project/0x7e917a2d0718401c9fe2a82f43ea558f5128f251b1e658c76dc7ff9a5e9fd993) program.\n\n## 📄 License\n\nThis project is licensed under MIT.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security\n\nThe PRBMath codebase has undergone audits by leading security experts from Cantina and Certora.\n\n| :warning: | Audits are not a guarantee of correctness. Some parts of the code base were modified after they were audited. |\n| --------- | :------------------------------------------------------------------------------------------------------------ |\n\nAll issues have been timely addressed and are fixed in the latest version of PRBMath.\n\n| Auditor | Type | Initial Commit                                                       | Report                                                                                                                            |\n| :------ | :--- | :------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------- |\n| Certora | Firm | [prb-math@v4.0.0](https://github.com/PaulRBerg/prb-math/tree/v4.0.0) | [2023-07-12](https://medium.com/certora/problems-in-solidity-fixed-point-libraries-certora-bug-disclosure-987f504daca4)           |\n| Cantina | Firm | [prb-math@v3.3.3](https://github.com/PaulRBerg/prb-math/tree/v3.3.2) | [2023-06-08](https://github.com/sablier-labs/audits/blob/6567df3fa42b90663e3e694b1e776c6db337a3f2/v2-core/cantina-2023-06-08.pdf) |\n\n## Cantina Review\n\nCantina performed an audit of [Sablier Lockup](https://github.com/sablier-labs/v2-core) in June 2023, which included `prb-math@v3.3.3` in scope. Their\nreport included a finding in PRBMath:\n\n> 3.2.3 PRBMath pow() function can return inconsistent values\n\nThe issue has been fixed in this PR: https://github.com/PaulRBerg/prb-math/pull/179\n\n## Certora Review\n\nThe rounding modes were not explicitly documented. This issue was fixed in [v4.0.1](https://github.com/PaulRBerg/prb-math/releases/tag/v4.0.1).\n"
  },
  {
    "path": "foundry.toml",
    "content": "# Full reference: https://github.com/foundry-rs/foundry/tree/master/crates/config\n\n[profile.default]\n  allow_internal_expect_revert = true\n  auto_detect_solc = false\n  bytecode_hash = \"ipfs\"\n  evm_version = \"shanghai\"            # needed for greater coverage of EVM chains\n  fuzz = { runs = 256 }\n  optimizer = true\n  optimizer_runs = 10_000\n  out = \"out\"\n  solc = \"0.8.30\"\n  src = \"src\"\n  test = \"test\"\n\n[profile.ci]\n  fuzz = { runs = 10_000, max_test_rejects = 100_000 }\n  verbosity = 3\n\n[fmt]\n  bracket_spacing = true\n  int_types = \"long\"\n  line_length = 132\n  multiline_func_header = \"all\"\n  number_underscore = \"preserve\"\n  quote_style = \"double\"\n  tab_width = 4\n  wrap_comments = true\n"
  },
  {
    "path": "funding.json",
    "content": "{\n  \"opRetro\": {\n    \"projectId\": \"0x7e917a2d0718401c9fe2a82f43ea558f5128f251b1e658c76dc7ff9a5e9fd993\"\n  }\n}\n"
  },
  {
    "path": "justfile",
    "content": "set allow-duplicate-variables\nset allow-duplicate-recipes\nset shell := [\"bash\", \"-euo\", \"pipefail\", \"-c\"]\nset unstable\n\n# ---------------------------------------------------------------------------- #\n#                                 DEPENDENCIES                                 #\n# ---------------------------------------------------------------------------- #\n\n# Bun: https://bun.sh\nbun := require(\"bun\")\n\n# Foundry: https://book.getfoundry.sh\nforge := require(\"forge\")\n\n# ---------------------------------------------------------------------------- #\n#                                   CONSTANTS                                  #\n# ---------------------------------------------------------------------------- #\n\nGLOBS_PRETTIER := \"\\\"**/*.{json,md,yml}\\\"\"\nGLOBS_SOLHINT := \"\\\"{src,test}/**/*.sol\\\"\"\n\n# ---------------------------------------------------------------------------- #\n#                                   COMMANDS                                   #\n# ---------------------------------------------------------------------------- #\n\n# Show available commands\ndefault:\n    @just --list\n\n# Build the project\n[group(\"commands\")]\n@build:\n    forge build\nalias b := build\n\n# Clean build artifacts\n[group(\"commands\")]\n@clean:\n    bunx del-cli cache out\nalias c := clean\n\n# Run tests\n[group(\"commands\")]\n@test *args:\n    forge test {{ args }}\nalias t := test\n\n# ---------------------------------------------------------------------------- #\n#                                    CHECKS                                    #\n# ---------------------------------------------------------------------------- #\n\n# Run all code checks\n[group(\"checks\")]\n@full-check:\n    just _run-with-status prettier-check\n    just _run-with-status solhint-check\n    just _run-with-status forge-check\n    echo \"\"\n    echo -e '{{ GREEN }}All code checks passed!{{ NORMAL }}'\nalias fc := full-check\n\n# Run all code fixes\n[group(\"checks\")]\n@full-write:\n    just _run-with-status prettier-write\n    just _run-with-status solhint-write\n    just _run-with-status forge-write\n    echo \"\"\n    echo -e '{{ GREEN }}All code fixes applied!{{ NORMAL }}'\nalias fw := full-write\n\n# Check Forge formatting\n[group(\"checks\")]\n@forge-check:\n    forge fmt --check\nalias fgc := forge-check\n\n# Format with Forge\n[group(\"checks\")]\n@forge-write:\n    forge fmt\nalias fgw := forge-write\n\n# Check Prettier formatting\n[group(\"checks\")]\n@prettier-check +globs=GLOBS_PRETTIER:\n    bun prettier --check --cache {{ globs }}\nalias pc := prettier-check\n\n# Format with Prettier\n[group(\"checks\")]\n@prettier-write +globs=GLOBS_PRETTIER:\n    bun prettier --write --cache {{ globs }}\nalias pw := prettier-write\n\n# Check Solhint linting\n[group(\"checks\")]\n@solhint-check +globs=GLOBS_SOLHINT:\n    bun solhint {{ globs }}\nalias shc := solhint-check\n\n# Fix Solhint issues\n[group(\"checks\")]\n@solhint-write +globs=GLOBS_SOLHINT:\n    bun solhint --fix {{ globs }}\nalias shw := solhint-write\n\n# ---------------------------------------------------------------------------- #\n#                                   UTILITIES                                  #\n# ---------------------------------------------------------------------------- #\n\n# Private recipe to run a check with formatted output\n@_run-with-status recipe:\n    echo \"\"\n    echo -e '{{ CYAN }}→ Running {{ recipe }}...{{ NORMAL }}'\n    just {{ recipe }}\n    echo -e '{{ GREEN }}✓ {{ recipe }} completed{{ NORMAL }}'\nalias rws := _run-with-status\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@prb/math\",\n  \"description\": \"Solidity library for advanced fixed-point math\",\n  \"version\": \"4.1.1\",\n  \"author\": {\n    \"name\": \"Paul Razvan Berg\",\n    \"url\": \"https://github.com/PaulRBerg\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/PaulRBerg/prb-math/issues\"\n  },\n  \"devDependencies\": {\n    \"forge-std\": \"github:foundry-rs/forge-std#v1.9.7\",\n    \"prettier\": \"^3.7.4\",\n    \"solhint\": \"^6.0.2\"\n  },\n  \"files\": [\n    \"src\",\n    \"test/utils\",\n    \"CHANGELOG.md\"\n  ],\n  \"homepage\": \"https://github.com/PaulRBerg/prb-math#readme\",\n  \"keywords\": [\n    \"arithmetic\",\n    \"blockchain\",\n    \"ethereum\",\n    \"fixed-point\",\n    \"fixed-point-math\",\n    \"library\",\n    \"math\",\n    \"smart-contracts\",\n    \"solidity\"\n  ],\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/PaulRBerg/prb-math.git\"\n  }\n}\n"
  },
  {
    "path": "src/Common.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n// Common.sol\n//\n// Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not\n// always operate with SD59x18 and UD60x18 numbers.\n\n/*//////////////////////////////////////////////////////////////////////////\n                                CUSTOM ERRORS\n//////////////////////////////////////////////////////////////////////////*/\n\n/// @notice Thrown when the resultant value in {mulDiv} overflows uint256.\nerror PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);\n\n/// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.\nerror PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);\n\n/// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.\nerror PRBMath_MulDivSigned_InputTooSmall();\n\n/// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.\nerror PRBMath_MulDivSigned_Overflow(int256 x, int256 y);\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CONSTANTS\n//////////////////////////////////////////////////////////////////////////*/\n\n/// @dev The maximum value a uint128 number can have.\nuint128 constant MAX_UINT128 = type(uint128).max;\n\n/// @dev The maximum value a uint40 number can have.\nuint40 constant MAX_UINT40 = type(uint40).max;\n\n/// @dev The maximum value a uint64 number can have.\nuint64 constant MAX_UINT64 = type(uint64).max;\n\n/// @dev The unit number, which is the decimal precision of the fixed-point types.\nuint256 constant UNIT = 1e18;\n\n/// @dev The unit number inverted mod 2^256.\nuint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n/// @dev The largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant\n/// bit in the binary representation of `UNIT`.\nuint256 constant UNIT_LPOTD = 262144;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    FUNCTIONS\n//////////////////////////////////////////////////////////////////////////*/\n\n/// @notice Calculates the binary exponent of x using the binary fraction method.\n/// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693.\n/// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n/// @return result The result as an unsigned 60.18-decimal fixed-point number.\n/// @custom:smtchecker abstract-function-nondet\nfunction exp2(uint256 x) pure returns (uint256 result) {\n    unchecked {\n        // Start from 0.5 in the 192.64-bit fixed-point format.\n        result = 0x800000000000000000000000000000000000000000000000;\n\n        // The following logic multiplies the result by $\\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:\n        //\n        // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.\n        // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing\n        // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,\n        // we know that `x & 0xFF` is also 1.\n        if (x & 0xFF00000000000000 > 0) {\n            if (x & 0x8000000000000000 > 0) {\n                result = (result * 0x16A09E667F3BCC909) >> 64;\n            }\n            if (x & 0x4000000000000000 > 0) {\n                result = (result * 0x1306FE0A31B7152DF) >> 64;\n            }\n            if (x & 0x2000000000000000 > 0) {\n                result = (result * 0x1172B83C7D517ADCE) >> 64;\n            }\n            if (x & 0x1000000000000000 > 0) {\n                result = (result * 0x10B5586CF9890F62A) >> 64;\n            }\n            if (x & 0x800000000000000 > 0) {\n                result = (result * 0x1059B0D31585743AE) >> 64;\n            }\n            if (x & 0x400000000000000 > 0) {\n                result = (result * 0x102C9A3E778060EE7) >> 64;\n            }\n            if (x & 0x200000000000000 > 0) {\n                result = (result * 0x10163DA9FB33356D8) >> 64;\n            }\n            if (x & 0x100000000000000 > 0) {\n                result = (result * 0x100B1AFA5ABCBED61) >> 64;\n            }\n        }\n\n        if (x & 0xFF000000000000 > 0) {\n            if (x & 0x80000000000000 > 0) {\n                result = (result * 0x10058C86DA1C09EA2) >> 64;\n            }\n            if (x & 0x40000000000000 > 0) {\n                result = (result * 0x1002C605E2E8CEC50) >> 64;\n            }\n            if (x & 0x20000000000000 > 0) {\n                result = (result * 0x100162F3904051FA1) >> 64;\n            }\n            if (x & 0x10000000000000 > 0) {\n                result = (result * 0x1000B175EFFDC76BA) >> 64;\n            }\n            if (x & 0x8000000000000 > 0) {\n                result = (result * 0x100058BA01FB9F96D) >> 64;\n            }\n            if (x & 0x4000000000000 > 0) {\n                result = (result * 0x10002C5CC37DA9492) >> 64;\n            }\n            if (x & 0x2000000000000 > 0) {\n                result = (result * 0x1000162E525EE0547) >> 64;\n            }\n            if (x & 0x1000000000000 > 0) {\n                result = (result * 0x10000B17255775C04) >> 64;\n            }\n        }\n\n        if (x & 0xFF0000000000 > 0) {\n            if (x & 0x800000000000 > 0) {\n                result = (result * 0x1000058B91B5BC9AE) >> 64;\n            }\n            if (x & 0x400000000000 > 0) {\n                result = (result * 0x100002C5C89D5EC6D) >> 64;\n            }\n            if (x & 0x200000000000 > 0) {\n                result = (result * 0x10000162E43F4F831) >> 64;\n            }\n            if (x & 0x100000000000 > 0) {\n                result = (result * 0x100000B1721BCFC9A) >> 64;\n            }\n            if (x & 0x80000000000 > 0) {\n                result = (result * 0x10000058B90CF1E6E) >> 64;\n            }\n            if (x & 0x40000000000 > 0) {\n                result = (result * 0x1000002C5C863B73F) >> 64;\n            }\n            if (x & 0x20000000000 > 0) {\n                result = (result * 0x100000162E430E5A2) >> 64;\n            }\n            if (x & 0x10000000000 > 0) {\n                result = (result * 0x1000000B172183551) >> 64;\n            }\n        }\n\n        if (x & 0xFF00000000 > 0) {\n            if (x & 0x8000000000 > 0) {\n                result = (result * 0x100000058B90C0B49) >> 64;\n            }\n            if (x & 0x4000000000 > 0) {\n                result = (result * 0x10000002C5C8601CC) >> 64;\n            }\n            if (x & 0x2000000000 > 0) {\n                result = (result * 0x1000000162E42FFF0) >> 64;\n            }\n            if (x & 0x1000000000 > 0) {\n                result = (result * 0x10000000B17217FBB) >> 64;\n            }\n            if (x & 0x800000000 > 0) {\n                result = (result * 0x1000000058B90BFCE) >> 64;\n            }\n            if (x & 0x400000000 > 0) {\n                result = (result * 0x100000002C5C85FE3) >> 64;\n            }\n            if (x & 0x200000000 > 0) {\n                result = (result * 0x10000000162E42FF1) >> 64;\n            }\n            if (x & 0x100000000 > 0) {\n                result = (result * 0x100000000B17217F8) >> 64;\n            }\n        }\n\n        if (x & 0xFF000000 > 0) {\n            if (x & 0x80000000 > 0) {\n                result = (result * 0x10000000058B90BFC) >> 64;\n            }\n            if (x & 0x40000000 > 0) {\n                result = (result * 0x1000000002C5C85FE) >> 64;\n            }\n            if (x & 0x20000000 > 0) {\n                result = (result * 0x100000000162E42FF) >> 64;\n            }\n            if (x & 0x10000000 > 0) {\n                result = (result * 0x1000000000B17217F) >> 64;\n            }\n            if (x & 0x8000000 > 0) {\n                result = (result * 0x100000000058B90C0) >> 64;\n            }\n            if (x & 0x4000000 > 0) {\n                result = (result * 0x10000000002C5C860) >> 64;\n            }\n            if (x & 0x2000000 > 0) {\n                result = (result * 0x1000000000162E430) >> 64;\n            }\n            if (x & 0x1000000 > 0) {\n                result = (result * 0x10000000000B17218) >> 64;\n            }\n        }\n\n        if (x & 0xFF0000 > 0) {\n            if (x & 0x800000 > 0) {\n                result = (result * 0x1000000000058B90C) >> 64;\n            }\n            if (x & 0x400000 > 0) {\n                result = (result * 0x100000000002C5C86) >> 64;\n            }\n            if (x & 0x200000 > 0) {\n                result = (result * 0x10000000000162E43) >> 64;\n            }\n            if (x & 0x100000 > 0) {\n                result = (result * 0x100000000000B1721) >> 64;\n            }\n            if (x & 0x80000 > 0) {\n                result = (result * 0x10000000000058B91) >> 64;\n            }\n            if (x & 0x40000 > 0) {\n                result = (result * 0x1000000000002C5C8) >> 64;\n            }\n            if (x & 0x20000 > 0) {\n                result = (result * 0x100000000000162E4) >> 64;\n            }\n            if (x & 0x10000 > 0) {\n                result = (result * 0x1000000000000B172) >> 64;\n            }\n        }\n\n        if (x & 0xFF00 > 0) {\n            if (x & 0x8000 > 0) {\n                result = (result * 0x100000000000058B9) >> 64;\n            }\n            if (x & 0x4000 > 0) {\n                result = (result * 0x10000000000002C5D) >> 64;\n            }\n            if (x & 0x2000 > 0) {\n                result = (result * 0x1000000000000162E) >> 64;\n            }\n            if (x & 0x1000 > 0) {\n                result = (result * 0x10000000000000B17) >> 64;\n            }\n            if (x & 0x800 > 0) {\n                result = (result * 0x1000000000000058C) >> 64;\n            }\n            if (x & 0x400 > 0) {\n                result = (result * 0x100000000000002C6) >> 64;\n            }\n            if (x & 0x200 > 0) {\n                result = (result * 0x10000000000000163) >> 64;\n            }\n            if (x & 0x100 > 0) {\n                result = (result * 0x100000000000000B1) >> 64;\n            }\n        }\n\n        if (x & 0xFF > 0) {\n            if (x & 0x80 > 0) {\n                result = (result * 0x10000000000000059) >> 64;\n            }\n            if (x & 0x40 > 0) {\n                result = (result * 0x1000000000000002C) >> 64;\n            }\n            if (x & 0x20 > 0) {\n                result = (result * 0x10000000000000016) >> 64;\n            }\n            if (x & 0x10 > 0) {\n                result = (result * 0x1000000000000000B) >> 64;\n            }\n            if (x & 0x8 > 0) {\n                result = (result * 0x10000000000000006) >> 64;\n            }\n            if (x & 0x4 > 0) {\n                result = (result * 0x10000000000000003) >> 64;\n            }\n            if (x & 0x2 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n            if (x & 0x1 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n        }\n\n        // In the code snippet below, two operations are executed simultaneously:\n        //\n        // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1\n        // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.\n        // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.\n        //\n        // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the\n        // integer part, $2^n$.\n        result *= UNIT;\n        result >>= (191 - (x >> 64));\n    }\n}\n\n/// @notice Finds the zero-based index of the first 1 in the binary representation of x.\n///\n/// @dev See the note on \"msb\" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set\n///\n/// The implementation satisfies these properties:\n///\n/// $$\n/// \\begin{cases}\n///   x = 0 \\implies \\text{msb}(x) = 0 \\\\\n///   x > 0 \\implies x \\gg \\text{msb}(x) = 1\n/// \\end{cases}\n/// $$\n///\n/// Each step below is equivalent to this high-level code:\n///\n/// ```solidity\n/// if (x >= 2 ** 128) {\n///     x >>= 128;\n///     result += 128;\n/// }\n/// ```\n///\n/// Where 128 is replaced with each respective power of two factor. The Yul instructions used below are:\n///\n/// - \"gt\" is \"greater than\"\n/// - \"or\" is the OR bitwise operator\n/// - \"shl\" is \"shift left\"\n/// - \"shr\" is \"shift right\"\n///\n/// See the full high-level implementation here:\n/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948\n///\n/// @param x The uint256 number for which to find the index of the most significant bit.\n/// @return result The index of the most significant bit as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction msb(uint256 x) pure returns (uint256 result) {\n    // 2^128\n    assembly (\"memory-safe\") {\n        let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^64\n    assembly (\"memory-safe\") {\n        let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^32\n    assembly (\"memory-safe\") {\n        let factor := shl(5, gt(x, 0xFFFFFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^16\n    assembly (\"memory-safe\") {\n        let factor := shl(4, gt(x, 0xFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^8\n    assembly (\"memory-safe\") {\n        let factor := shl(3, gt(x, 0xFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^4\n    assembly (\"memory-safe\") {\n        let factor := shl(2, gt(x, 0xF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^2\n    assembly (\"memory-safe\") {\n        let factor := shl(1, gt(x, 0x3))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^1\n    // No need to shift x any more.\n    assembly (\"memory-safe\") {\n        let factor := gt(x, 0x1)\n        result := or(result, factor)\n    }\n}\n\n/// @notice Calculates x*y÷denominator with 512-bit precision.\n///\n/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n///\n/// Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - The denominator must not be zero.\n/// - The result must fit in uint256.\n///\n/// @param x The multiplicand as a uint256.\n/// @param y The multiplier as a uint256.\n/// @param denominator The divisor as a uint256.\n/// @return result The result as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {\n    // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n    // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256\n    // variables such that product = prod1 * 2^256 + prod0.\n    uint256 prod0; // Least significant 256 bits of the product\n    uint256 prod1; // Most significant 256 bits of the product\n    assembly (\"memory-safe\") {\n        let mm := mulmod(x, y, not(0))\n        prod0 := mul(x, y)\n        prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n    }\n\n    // Handle non-overflow cases, 256 by 256 division.\n    if (prod1 == 0) {\n        unchecked {\n            return prod0 / denominator;\n        }\n    }\n\n    // Make sure the result is less than 2^256. Also prevents denominator == 0.\n    if (prod1 >= denominator) {\n        revert PRBMath_MulDiv_Overflow(x, y, denominator);\n    }\n\n    ////////////////////////////////////////////////////////////////////////////\n    // 512 by 256 division\n    ////////////////////////////////////////////////////////////////////////////\n\n    // Make division exact by subtracting the remainder from [prod1 prod0].\n    uint256 remainder;\n    assembly (\"memory-safe\") {\n        // Compute remainder using the mulmod Yul instruction.\n        remainder := mulmod(x, y, denominator)\n\n        // Subtract 256 bit number from 512-bit number.\n        prod1 := sub(prod1, gt(remainder, prod0))\n        prod0 := sub(prod0, remainder)\n    }\n\n    unchecked {\n        // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow\n        // because the denominator cannot be zero at this point in the function execution. The result is always >= 1.\n        // For more detail, see https://cs.stackexchange.com/q/138556/92363.\n        uint256 lpotdod = denominator & (~denominator + 1);\n        uint256 flippedLpotdod;\n\n        assembly (\"memory-safe\") {\n            // Factor powers of two out of denominator.\n            denominator := div(denominator, lpotdod)\n\n            // Divide [prod1 prod0] by lpotdod.\n            prod0 := div(prod0, lpotdod)\n\n            // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.\n            // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.\n            // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693\n            flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n        }\n\n        // Shift in bits from prod1 into prod0.\n        prod0 |= prod1 * flippedLpotdod;\n\n        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n        // four bits. That is, denominator * inv = 1 mod 2^4.\n        uint256 inverse = (3 * denominator) ^ 2;\n\n        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n        // in modular arithmetic, doubling the correct bits in each step.\n        inverse *= 2 - denominator * inverse; // inverse mod 2^8\n        inverse *= 2 - denominator * inverse; // inverse mod 2^16\n        inverse *= 2 - denominator * inverse; // inverse mod 2^32\n        inverse *= 2 - denominator * inverse; // inverse mod 2^64\n        inverse *= 2 - denominator * inverse; // inverse mod 2^128\n        inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n        // is no longer required.\n        result = prod0 * inverse;\n    }\n}\n\n/// @notice Calculates x*y÷1e18 with 512-bit precision.\n///\n/// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.\n///\n/// Notes:\n/// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.\n/// - The result is rounded toward zero.\n/// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:\n///\n/// $$\n/// \\begin{cases}\n///   x * y = {MAX\\_UINT256} * {UNIT} \\\\\n///   (x * y) \\% {UNIT} \\geq \\frac{UNIT}{2}\n/// \\end{cases}\n/// $$\n///\n/// Requirements:\n/// - Refer to the requirements in {mulDiv}.\n/// - The result must fit in uint256.\n///\n/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n/// @return result The result as an unsigned 60.18-decimal fixed-point number.\n/// @custom:smtchecker abstract-function-nondet\nfunction mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {\n    uint256 prod0;\n    uint256 prod1;\n    assembly (\"memory-safe\") {\n        let mm := mulmod(x, y, not(0))\n        prod0 := mul(x, y)\n        prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n    }\n\n    if (prod1 == 0) {\n        unchecked {\n            return prod0 / UNIT;\n        }\n    }\n\n    if (prod1 >= UNIT) {\n        revert PRBMath_MulDiv18_Overflow(x, y);\n    }\n\n    uint256 remainder;\n    assembly (\"memory-safe\") {\n        remainder := mulmod(x, y, UNIT)\n        result := mul(\n            or(\n                div(sub(prod0, remainder), UNIT_LPOTD),\n                mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))\n            ),\n            UNIT_INVERSE\n        )\n    }\n}\n\n/// @notice Calculates x*y÷denominator with 512-bit precision.\n///\n/// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.\n///\n/// Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - Refer to the requirements in {mulDiv}.\n/// - None of the inputs can be `type(int256).min`.\n/// - The result must fit in int256.\n///\n/// @param x The multiplicand as an int256.\n/// @param y The multiplier as an int256.\n/// @param denominator The divisor as an int256.\n/// @return result The result as an int256.\n/// @custom:smtchecker abstract-function-nondet\nfunction mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {\n    if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n        revert PRBMath_MulDivSigned_InputTooSmall();\n    }\n\n    // Get hold of the absolute values of x, y and the denominator.\n    uint256 xAbs;\n    uint256 yAbs;\n    uint256 dAbs;\n    unchecked {\n        xAbs = x < 0 ? uint256(-x) : uint256(x);\n        yAbs = y < 0 ? uint256(-y) : uint256(y);\n        dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n    }\n\n    // Compute the absolute value of x*y÷denominator. The result must fit in int256.\n    uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);\n    if (resultAbs > uint256(type(int256).max)) {\n        revert PRBMath_MulDivSigned_Overflow(x, y);\n    }\n\n    // Get the signs of x, y and the denominator.\n    uint256 sx;\n    uint256 sy;\n    uint256 sd;\n    assembly (\"memory-safe\") {\n        // \"sgt\" is the \"signed greater than\" assembly instruction and \"sub(0,1)\" is -1 in two's complement.\n        sx := sgt(x, sub(0, 1))\n        sy := sgt(y, sub(0, 1))\n        sd := sgt(denominator, sub(0, 1))\n    }\n\n    // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.\n    // If there are, the result should be negative. Otherwise, it should be positive.\n    unchecked {\n        result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);\n    }\n}\n\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// The implementation satisfies these properties:\n///\n/// $$\n/// \\begin{cases}\n///   \\lfloor\\sqrt{x}\\rfloor \\leq \\sqrt{x} < \\lfloor\\sqrt{x}\\rfloor + 1 \\\\[0.5em]\n///   \\lfloor\\sqrt{x}\\rfloor^2 \\leq x < (\\lfloor\\sqrt{x}\\rfloor + 1)^2\n/// \\end{cases}\n/// $$\n///\n/// Notes:\n/// - If x is not a perfect square, the result is rounded down.\n/// - Credits to OpenZeppelin for the explanations in comments below.\n///\n/// @param x The uint256 number for which to calculate the square root.\n/// @return result The result as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction sqrt(uint256 x) pure returns (uint256 result) {\n    if (x == 0) {\n        return 0;\n    }\n\n    // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.\n    //\n    // We know that the \"msb\" (most significant bit) of x is a power of 2 such that we have:\n    //\n    // $$\n    // msb(x) <= x <= 2*msb(x)\n    // $$\n    //\n    // We write $msb(x)$ as $2^k$, and we get:\n    //\n    // $$\n    // k = log_2(x)\n    // $$\n    //\n    // Thus, we can write the initial inequality as:\n    //\n    // $$\n    // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\\\\n    // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\\\\n    // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}\n    // $$\n    //\n    // Consequently, $2^{log_2(x) / 2}$ is a good first approximation of sqrt(x) with at least one correct bit.\n    uint256 xAux = uint256(x);\n    result = 1;\n    if (xAux >= 2 ** 128) {\n        xAux >>= 128;\n        result <<= 64;\n    }\n    if (xAux >= 2 ** 64) {\n        xAux >>= 64;\n        result <<= 32;\n    }\n    if (xAux >= 2 ** 32) {\n        xAux >>= 32;\n        result <<= 16;\n    }\n    if (xAux >= 2 ** 16) {\n        xAux >>= 16;\n        result <<= 8;\n    }\n    if (xAux >= 2 ** 8) {\n        xAux >>= 8;\n        result <<= 4;\n    }\n    if (xAux >= 2 ** 4) {\n        xAux >>= 4;\n        result <<= 2;\n    }\n    if (xAux >= 2 ** 2) {\n        result <<= 1;\n    }\n\n    // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at\n    // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision\n    // doubles at every iteration). We thus need at most 7 iterations to turn our partial result with one bit of\n    // precision into the expected uint128 result.\n    unchecked {\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n\n        // If x is not a perfect square, round the result toward zero.\n        uint256 roundedResult = x / result;\n        if (result >= roundedResult) {\n            result = roundedResult;\n        }\n    }\n}\n"
  },
  {
    "path": "src/SD1x18.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n/*\n\n██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗\n██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║\n██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║\n██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║\n██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝\n\n███████╗██████╗  ██╗██╗  ██╗ ██╗ █████╗\n██╔════╝██╔══██╗███║╚██╗██╔╝███║██╔══██╗\n███████╗██║  ██║╚██║ ╚███╔╝ ╚██║╚█████╔╝\n╚════██║██║  ██║ ██║ ██╔██╗  ██║██╔══██╗\n███████║██████╔╝ ██║██╔╝ ██╗ ██║╚█████╔╝\n╚══════╝╚═════╝  ╚═╝╚═╝  ╚═╝ ╚═╝ ╚════╝\n\n*/\n\nimport \"./sd1x18/Casting.sol\";\nimport \"./sd1x18/Constants.sol\";\nimport \"./sd1x18/Errors.sol\";\nimport \"./sd1x18/ValueType.sol\";\n"
  },
  {
    "path": "src/SD21x18.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n/*\n\n██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗\n██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║\n██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║\n██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║\n██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝\n\n███████╗██████╗ ██████╗  ██╗██╗  ██╗ ██╗ █████╗\n██╔════╝██╔══██╗╚════██╗███║╚██╗██╔╝███║██╔══██╗\n███████╗██║  ██║ █████╔╝╚██║ ╚███╔╝ ╚██║╚█████╔╝\n╚════██║██║  ██║██╔═══╝  ██║ ██╔██╗  ██║██╔══██╗\n███████║██████╔╝███████╗ ██║██╔╝ ██╗ ██║╚█████╔╝\n╚══════╝╚═════╝ ╚══════╝ ╚═╝╚═╝  ╚═╝ ╚═╝ ╚════╝\n\n*/\n\nimport \"./sd21x18/Casting.sol\";\nimport \"./sd21x18/Constants.sol\";\nimport \"./sd21x18/Errors.sol\";\nimport \"./sd21x18/ValueType.sol\";\n"
  },
  {
    "path": "src/SD59x18.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n/*\n\n██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗\n██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║\n██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║\n██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║\n██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝\n\n███████╗██████╗ ███████╗ █████╗ ██╗  ██╗ ██╗ █████╗\n██╔════╝██╔══██╗██╔════╝██╔══██╗╚██╗██╔╝███║██╔══██╗\n███████╗██║  ██║███████╗╚██████║ ╚███╔╝ ╚██║╚█████╔╝\n╚════██║██║  ██║╚════██║ ╚═══██║ ██╔██╗  ██║██╔══██╗\n███████║██████╔╝███████║ █████╔╝██╔╝ ██╗ ██║╚█████╔╝\n╚══════╝╚═════╝ ╚══════╝ ╚════╝ ╚═╝  ╚═╝ ╚═╝ ╚════╝\n\n*/\n\nimport \"./sd59x18/Casting.sol\";\nimport \"./sd59x18/Constants.sol\";\nimport \"./sd59x18/Conversions.sol\";\nimport \"./sd59x18/Errors.sol\";\nimport \"./sd59x18/Helpers.sol\";\nimport \"./sd59x18/Math.sol\";\nimport \"./sd59x18/ValueType.sol\";\n"
  },
  {
    "path": "src/UD21x18.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n/*\n\n██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗\n██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║\n██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║\n██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║\n██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝\n\n██╗   ██╗██████╗ ██████╗  ██╗██╗  ██╗ ██╗ █████╗\n██║   ██║██╔══██╗╚════██╗███║╚██╗██╔╝███║██╔══██╗\n██║   ██║██║  ██║ █████╔╝╚██║ ╚███╔╝ ╚██║╚█████╔╝\n██║   ██║██║  ██║██╔═══╝  ██║ ██╔██╗  ██║██╔══██╗\n╚██████╔╝██████╔╝███████╗ ██║██╔╝ ██╗ ██║╚█████╔╝\n ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝╚═╝  ╚═╝ ╚═╝ ╚════╝\n\n*/\n\nimport \"./ud21x18/Casting.sol\";\nimport \"./ud21x18/Constants.sol\";\nimport \"./ud21x18/Errors.sol\";\nimport \"./ud21x18/ValueType.sol\";\n"
  },
  {
    "path": "src/UD2x18.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n/*\n\n██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗\n██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║\n██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║\n██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║\n██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝\n\n██╗   ██╗██████╗ ██████╗ ██╗  ██╗ ██╗ █████╗\n██║   ██║██╔══██╗╚════██╗╚██╗██╔╝███║██╔══██╗\n██║   ██║██║  ██║ █████╔╝ ╚███╔╝ ╚██║╚█████╔╝\n██║   ██║██║  ██║██╔═══╝  ██╔██╗  ██║██╔══██╗\n╚██████╔╝██████╔╝███████╗██╔╝ ██╗ ██║╚█████╔╝\n ╚═════╝ ╚═════╝ ╚══════╝╚═╝  ╚═╝ ╚═╝ ╚════╝\n\n*/\n\nimport \"./ud2x18/Casting.sol\";\nimport \"./ud2x18/Constants.sol\";\nimport \"./ud2x18/Errors.sol\";\nimport \"./ud2x18/ValueType.sol\";\n"
  },
  {
    "path": "src/UD60x18.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n/*\n\n██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗\n██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║\n██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║\n██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║\n██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝\n\n██╗   ██╗██████╗  ██████╗  ██████╗ ██╗  ██╗ ██╗ █████╗\n██║   ██║██╔══██╗██╔════╝ ██╔═████╗╚██╗██╔╝███║██╔══██╗\n██║   ██║██║  ██║███████╗ ██║██╔██║ ╚███╔╝ ╚██║╚█████╔╝\n██║   ██║██║  ██║██╔═══██╗████╔╝██║ ██╔██╗  ██║██╔══██╗\n╚██████╔╝██████╔╝╚██████╔╝╚██████╔╝██╔╝ ██╗ ██║╚█████╔╝\n ╚═════╝ ╚═════╝  ╚═════╝  ╚═════╝ ╚═╝  ╚═╝ ╚═╝ ╚════╝\n\n*/\n\nimport \"./ud60x18/Casting.sol\";\nimport \"./ud60x18/Constants.sol\";\nimport \"./ud60x18/Conversions.sol\";\nimport \"./ud60x18/Errors.sol\";\nimport \"./ud60x18/Helpers.sol\";\nimport \"./ud60x18/Math.sol\";\nimport \"./ud60x18/ValueType.sol\";\n"
  },
  {
    "path": "src/casting/Uint128.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { uMAX_SD1x18 } from \"../sd1x18/Constants.sol\";\nimport { SD1x18 } from \"../sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18 } from \"../sd21x18/Constants.sol\";\nimport { SD21x18 } from \"../sd21x18/ValueType.sol\";\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"../ud2x18/Constants.sol\";\nimport { UD2x18 } from \"../ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"../ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\n\n/// @notice Thrown when trying to cast a uint128 that doesn't fit in SD1x18.\nerror PRBMath_IntoSD1x18_Overflow(uint128 x);\n\n/// @notice Thrown when trying to cast a uint128 that doesn't fit in SD21x18.\nerror PRBMath_IntoSD21x18_Overflow(uint128 x);\n\n/// @notice Thrown when trying to cast a uint128 that doesn't fit in UD2x18.\nerror PRBMath_IntoUD2x18_Overflow(uint128 x);\n\n/// @title PRBMathCastingUint128\n/// @notice Casting utilities for uint128.\nlibrary PRBMathCastingUint128 {\n    /// @notice Casts a uint128 number to SD1x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_SD1x18\n    function intoSD1x18(uint128 x) internal pure returns (SD1x18 result) {\n        if (x > uint256(int256(uMAX_SD1x18))) {\n            revert PRBMath_IntoSD1x18_Overflow(x);\n        }\n        result = SD1x18.wrap(int64(uint64(x)));\n    }\n\n    /// @notice Casts a uint128 number to SD21x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_SD21x18\n    function intoSD21x18(uint128 x) internal pure returns (SD21x18 result) {\n        if (x > uint256(int256(uMAX_SD21x18))) {\n            revert PRBMath_IntoSD21x18_Overflow(x);\n        }\n        result = SD21x18.wrap(int128(x));\n    }\n\n    /// @notice Casts a uint128 number to SD59x18.\n    /// @dev There is no overflow check because uint128 ⊆ SD59x18.\n    function intoSD59x18(uint128 x) internal pure returns (SD59x18 result) {\n        result = SD59x18.wrap(int256(uint256(x)));\n    }\n\n    /// @notice Casts a uint128 number to UD2x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_UD2x18\n    function intoUD2x18(uint128 x) internal pure returns (UD2x18 result) {\n        if (x > uint64(uMAX_UD2x18)) {\n            revert PRBMath_IntoUD2x18_Overflow(x);\n        }\n        result = UD2x18.wrap(uint64(x));\n    }\n\n    /// @notice Casts a uint128 number to UD21x18.\n    function intoUD21x18(uint128 x) internal pure returns (UD21x18 result) {\n        result = UD21x18.wrap(x);\n    }\n\n    /// @notice Casts a uint128 number to UD60x18.\n    /// @dev There is no overflow check because uint128 ⊆ UD60x18.\n    function intoUD60x18(uint128 x) internal pure returns (UD60x18 result) {\n        result = UD60x18.wrap(x);\n    }\n}\n"
  },
  {
    "path": "src/casting/Uint256.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { uMAX_SD1x18 } from \"../sd1x18/Constants.sol\";\nimport { SD1x18 } from \"../sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18 } from \"../sd21x18/Constants.sol\";\nimport { SD21x18 } from \"../sd21x18/ValueType.sol\";\nimport { uMAX_SD59x18 } from \"../sd59x18/Constants.sol\";\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"../ud2x18/Constants.sol\";\nimport { UD2x18 } from \"../ud2x18/ValueType.sol\";\nimport { uMAX_UD21x18 } from \"../ud21x18/Constants.sol\";\nimport { UD21x18 } from \"../ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\n\n/// @notice Thrown when trying to cast a uint256 that doesn't fit in SD1x18.\nerror PRBMath_IntoSD1x18_Overflow(uint256 x);\n\n/// @notice Thrown when trying to cast a uint256 that doesn't fit in SD21x18.\nerror PRBMath_IntoSD21x18_Overflow(uint256 x);\n\n/// @notice Thrown when trying to cast a uint256 that doesn't fit in SD59x18.\nerror PRBMath_IntoSD59x18_Overflow(uint256 x);\n\n/// @notice Thrown when trying to cast a uint256 that doesn't fit in UD2x18.\nerror PRBMath_IntoUD2x18_Overflow(uint256 x);\n\n/// @notice Thrown when trying to cast a uint256 that doesn't fit in UD21x18.\nerror PRBMath_IntoUD21x18_Overflow(uint256 x);\n\n/// @title PRBMathCastingUint256\n/// @notice Casting utilities for uint256.\nlibrary PRBMathCastingUint256 {\n    /// @notice Casts a uint256 number to SD1x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_SD1x18\n    function intoSD1x18(uint256 x) internal pure returns (SD1x18 result) {\n        if (x > uint256(int256(uMAX_SD1x18))) {\n            revert PRBMath_IntoSD1x18_Overflow(x);\n        }\n        result = SD1x18.wrap(int64(int256(x)));\n    }\n\n    /// @notice Casts a uint256 number to SD21x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_SD21x18\n    function intoSD21x18(uint256 x) internal pure returns (SD21x18 result) {\n        if (x > uint256(int256(uMAX_SD21x18))) {\n            revert PRBMath_IntoSD21x18_Overflow(x);\n        }\n        result = SD21x18.wrap(int128(int256(x)));\n    }\n\n    /// @notice Casts a uint256 number to SD59x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_SD59x18\n    function intoSD59x18(uint256 x) internal pure returns (SD59x18 result) {\n        if (x > uint256(uMAX_SD59x18)) {\n            revert PRBMath_IntoSD59x18_Overflow(x);\n        }\n        result = SD59x18.wrap(int256(x));\n    }\n\n    /// @notice Casts a uint256 number to UD2x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_UD2x18\n    function intoUD2x18(uint256 x) internal pure returns (UD2x18 result) {\n        if (x > uint256(uMAX_UD2x18)) {\n            revert PRBMath_IntoUD2x18_Overflow(x);\n        }\n        result = UD2x18.wrap(uint64(x));\n    }\n\n    /// @notice Casts a uint256 number to UD2x18.\n    /// @dev Requirements:\n    /// - x ≤ uMAX_UD21x18\n    function intoUD21x18(uint256 x) internal pure returns (UD21x18 result) {\n        if (x > uint256(uMAX_UD21x18)) {\n            revert PRBMath_IntoUD21x18_Overflow(x);\n        }\n        result = UD21x18.wrap(uint128(x));\n    }\n\n    /// @notice Casts a uint256 number to UD60x18.\n    function intoUD60x18(uint256 x) internal pure returns (UD60x18 result) {\n        result = UD60x18.wrap(x);\n    }\n}\n"
  },
  {
    "path": "src/casting/Uint40.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { SD1x18 } from \"../sd1x18/ValueType.sol\";\nimport { SD21x18 } from \"../sd21x18/ValueType.sol\";\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { UD2x18 } from \"../ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"../ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\n\n/// @title PRBMathCastingUint40\n/// @notice Casting utilities for uint40.\nlibrary PRBMathCastingUint40 {\n    /// @notice Casts a uint40 number into SD1x18.\n    /// @dev There is no overflow check because uint40 ⊆ SD1x18.\n    function intoSD1x18(uint40 x) internal pure returns (SD1x18 result) {\n        result = SD1x18.wrap(int64(uint64(x)));\n    }\n\n    /// @notice Casts a uint40 number into SD21x18.\n    /// @dev There is no overflow check because uint40 ⊆ SD21x18.\n    function intoSD21x18(uint40 x) internal pure returns (SD21x18 result) {\n        result = SD21x18.wrap(int128(uint128(x)));\n    }\n\n    /// @notice Casts a uint40 number into SD59x18.\n    /// @dev There is no overflow check because uint40 ⊆ SD59x18.\n    function intoSD59x18(uint40 x) internal pure returns (SD59x18 result) {\n        result = SD59x18.wrap(int256(uint256(x)));\n    }\n\n    /// @notice Casts a uint40 number into UD2x18.\n    /// @dev There is no overflow check because uint40 ⊆ UD2x18.\n    function intoUD2x18(uint40 x) internal pure returns (UD2x18 result) {\n        result = UD2x18.wrap(x);\n    }\n\n    /// @notice Casts a uint40 number into UD21x18.\n    /// @dev There is no overflow check because uint40 ⊆ UD21x18.\n    function intoUD21x18(uint40 x) internal pure returns (UD21x18 result) {\n        result = UD21x18.wrap((x));\n    }\n\n    /// @notice Casts a uint40 number into UD60x18.\n    /// @dev There is no overflow check because uint40 ⊆ UD60x18.\n    function intoUD60x18(uint40 x) internal pure returns (UD60x18 result) {\n        result = UD60x18.wrap(x);\n    }\n}\n"
  },
  {
    "path": "src/sd1x18/Casting.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"../Common.sol\" as Common;\nimport \"./Errors.sol\" as CastingErrors;\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\nimport { SD1x18 } from \"./ValueType.sol\";\n\n/// @notice Casts an SD1x18 number into SD59x18.\n/// @dev There is no overflow check because SD1x18 ⊆ SD59x18.\nfunction intoSD59x18(SD1x18 x) pure returns (SD59x18 result) {\n    result = SD59x18.wrap(int256(SD1x18.unwrap(x)));\n}\n\n/// @notice Casts an SD1x18 number into UD60x18.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUD60x18(SD1x18 x) pure returns (UD60x18 result) {\n    int64 xInt = SD1x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD1x18_ToUD60x18_Underflow(x);\n    }\n    result = UD60x18.wrap(uint64(xInt));\n}\n\n/// @notice Casts an SD1x18 number into uint128.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUint128(SD1x18 x) pure returns (uint128 result) {\n    int64 xInt = SD1x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD1x18_ToUint128_Underflow(x);\n    }\n    result = uint128(uint64(xInt));\n}\n\n/// @notice Casts an SD1x18 number into uint256.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUint256(SD1x18 x) pure returns (uint256 result) {\n    int64 xInt = SD1x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD1x18_ToUint256_Underflow(x);\n    }\n    result = uint256(uint64(xInt));\n}\n\n/// @notice Casts an SD1x18 number into uint40.\n/// @dev Requirements:\n/// - x ≥ 0\n/// - x ≤ MAX_UINT40\nfunction intoUint40(SD1x18 x) pure returns (uint40 result) {\n    int64 xInt = SD1x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD1x18_ToUint40_Underflow(x);\n    }\n    if (xInt > int64(uint64(Common.MAX_UINT40))) {\n        revert CastingErrors.PRBMath_SD1x18_ToUint40_Overflow(x);\n    }\n    result = uint40(uint64(xInt));\n}\n\n/// @notice Alias for {wrap}.\nfunction sd1x18(int64 x) pure returns (SD1x18 result) {\n    result = SD1x18.wrap(x);\n}\n\n/// @notice Unwraps an SD1x18 number into int64.\nfunction unwrap(SD1x18 x) pure returns (int64 result) {\n    result = SD1x18.unwrap(x);\n}\n\n/// @notice Wraps an int64 number into SD1x18.\nfunction wrap(int64 x) pure returns (SD1x18 result) {\n    result = SD1x18.wrap(x);\n}\n"
  },
  {
    "path": "src/sd1x18/Constants.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { SD1x18 } from \"./ValueType.sol\";\n\n/// @dev Euler's number as an SD1x18 number.\nSD1x18 constant E = SD1x18.wrap(2_718281828459045235);\n\n/// @dev The maximum value an SD1x18 number can have.\nint64 constant uMAX_SD1x18 = 9_223372036854775807;\nSD1x18 constant MAX_SD1x18 = SD1x18.wrap(uMAX_SD1x18);\n\n/// @dev The minimum value an SD1x18 number can have.\nint64 constant uMIN_SD1x18 = -9_223372036854775808;\nSD1x18 constant MIN_SD1x18 = SD1x18.wrap(uMIN_SD1x18);\n\n/// @dev PI as an SD1x18 number.\nSD1x18 constant PI = SD1x18.wrap(3_141592653589793238);\n\n/// @dev The unit number, which gives the decimal precision of SD1x18.\nSD1x18 constant UNIT = SD1x18.wrap(1e18);\nint64 constant uUNIT = 1e18;\n"
  },
  {
    "path": "src/sd1x18/Errors.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { SD1x18 } from \"./ValueType.sol\";\n\n/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in UD60x18.\nerror PRBMath_SD1x18_ToUD60x18_Underflow(SD1x18 x);\n\n/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint128.\nerror PRBMath_SD1x18_ToUint128_Underflow(SD1x18 x);\n\n/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint256.\nerror PRBMath_SD1x18_ToUint256_Underflow(SD1x18 x);\n\n/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40.\nerror PRBMath_SD1x18_ToUint40_Overflow(SD1x18 x);\n\n/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40.\nerror PRBMath_SD1x18_ToUint40_Underflow(SD1x18 x);\n"
  },
  {
    "path": "src/sd1x18/ValueType.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Casting.sol\" as Casting;\n\n/// @notice The signed 1.18-decimal fixed-point number representation, which can have up to 1 digit and up to 18\n/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity\n/// type int64. This is useful when end users want to use int64 to save gas, e.g. with tight variable packing in contract\n/// storage.\ntype SD1x18 is int64;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CASTING\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Casting.intoSD59x18,\n    Casting.intoUD60x18,\n    Casting.intoUint128,\n    Casting.intoUint256,\n    Casting.intoUint40,\n    Casting.unwrap\n} for SD1x18 global;\n"
  },
  {
    "path": "src/sd21x18/Casting.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"../Common.sol\" as Common;\nimport \"./Errors.sol\" as CastingErrors;\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\nimport { SD21x18 } from \"./ValueType.sol\";\n\n/// @notice Casts an SD21x18 number into SD59x18.\n/// @dev There is no overflow check because SD21x18 ⊆ SD59x18.\nfunction intoSD59x18(SD21x18 x) pure returns (SD59x18 result) {\n    result = SD59x18.wrap(int256(SD21x18.unwrap(x)));\n}\n\n/// @notice Casts an SD21x18 number into UD60x18.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUD60x18(SD21x18 x) pure returns (UD60x18 result) {\n    int128 xInt = SD21x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD21x18_ToUD60x18_Underflow(x);\n    }\n    result = UD60x18.wrap(uint128(xInt));\n}\n\n/// @notice Casts an SD21x18 number into uint128.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUint128(SD21x18 x) pure returns (uint128 result) {\n    int128 xInt = SD21x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD21x18_ToUint128_Underflow(x);\n    }\n    result = uint128(xInt);\n}\n\n/// @notice Casts an SD21x18 number into uint256.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUint256(SD21x18 x) pure returns (uint256 result) {\n    int128 xInt = SD21x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD21x18_ToUint256_Underflow(x);\n    }\n    result = uint256(uint128(xInt));\n}\n\n/// @notice Casts an SD21x18 number into uint40.\n/// @dev Requirements:\n/// - x ≥ 0\n/// - x ≤ MAX_UINT40\nfunction intoUint40(SD21x18 x) pure returns (uint40 result) {\n    int128 xInt = SD21x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD21x18_ToUint40_Underflow(x);\n    }\n    if (xInt > int128(uint128(Common.MAX_UINT40))) {\n        revert CastingErrors.PRBMath_SD21x18_ToUint40_Overflow(x);\n    }\n    result = uint40(uint128(xInt));\n}\n\n/// @notice Alias for {wrap}.\nfunction sd21x18(int128 x) pure returns (SD21x18 result) {\n    result = SD21x18.wrap(x);\n}\n\n/// @notice Unwraps an SD21x18 number into int128.\nfunction unwrap(SD21x18 x) pure returns (int128 result) {\n    result = SD21x18.unwrap(x);\n}\n\n/// @notice Wraps an int128 number into SD21x18.\nfunction wrap(int128 x) pure returns (SD21x18 result) {\n    result = SD21x18.wrap(x);\n}\n"
  },
  {
    "path": "src/sd21x18/Constants.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { SD21x18 } from \"./ValueType.sol\";\n\n/// @dev Euler's number as an SD21x18 number.\nSD21x18 constant E = SD21x18.wrap(2_718281828459045235);\n\n/// @dev The maximum value an SD21x18 number can have.\nint128 constant uMAX_SD21x18 = 170141183460469231731_687303715884105727;\nSD21x18 constant MAX_SD21x18 = SD21x18.wrap(uMAX_SD21x18);\n\n/// @dev The minimum value an SD21x18 number can have.\nint128 constant uMIN_SD21x18 = -170141183460469231731_687303715884105728;\nSD21x18 constant MIN_SD21x18 = SD21x18.wrap(uMIN_SD21x18);\n\n/// @dev PI as an SD21x18 number.\nSD21x18 constant PI = SD21x18.wrap(3_141592653589793238);\n\n/// @dev The unit number, which gives the decimal precision of SD21x18.\nSD21x18 constant UNIT = SD21x18.wrap(1e18);\nint128 constant uUNIT = 1e18;\n"
  },
  {
    "path": "src/sd21x18/Errors.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { SD21x18 } from \"./ValueType.sol\";\n\n/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint128.\nerror PRBMath_SD21x18_ToUint128_Underflow(SD21x18 x);\n\n/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in UD60x18.\nerror PRBMath_SD21x18_ToUD60x18_Underflow(SD21x18 x);\n\n/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint256.\nerror PRBMath_SD21x18_ToUint256_Underflow(SD21x18 x);\n\n/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint40.\nerror PRBMath_SD21x18_ToUint40_Overflow(SD21x18 x);\n\n/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint40.\nerror PRBMath_SD21x18_ToUint40_Underflow(SD21x18 x);\n"
  },
  {
    "path": "src/sd21x18/ValueType.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Casting.sol\" as Casting;\n\n/// @notice The signed 21.18-decimal fixed-point number representation, which can have up to 21 digits and up to 18\n/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity\n/// type int128. This is useful when end users want to use int128 to save gas, e.g. with tight variable packing in contract\n/// storage.\ntype SD21x18 is int128;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CASTING\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Casting.intoSD59x18,\n    Casting.intoUD60x18,\n    Casting.intoUint128,\n    Casting.intoUint256,\n    Casting.intoUint40,\n    Casting.unwrap\n} for SD21x18 global;\n"
  },
  {
    "path": "src/sd59x18/Casting.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Errors.sol\" as CastingErrors;\nimport { MAX_UINT128, MAX_UINT40 } from \"../Common.sol\";\nimport { uMAX_SD1x18, uMIN_SD1x18 } from \"../sd1x18/Constants.sol\";\nimport { SD1x18 } from \"../sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18, uMIN_SD21x18 } from \"../sd21x18/Constants.sol\";\nimport { SD21x18 } from \"../sd21x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"../ud2x18/Constants.sol\";\nimport { UD2x18 } from \"../ud2x18/ValueType.sol\";\nimport { uMAX_UD21x18 } from \"../ud21x18/Constants.sol\";\nimport { UD21x18 } from \"../ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\nimport { SD59x18 } from \"./ValueType.sol\";\n\n/// @notice Casts an SD59x18 number into int256.\n/// @dev This is basically a functional alias for {unwrap}.\nfunction intoInt256(SD59x18 x) pure returns (int256 result) {\n    result = SD59x18.unwrap(x);\n}\n\n/// @notice Casts an SD59x18 number into SD1x18.\n/// @dev Requirements:\n/// - x ≥ uMIN_SD1x18\n/// - x ≤ uMAX_SD1x18\nfunction intoSD1x18(SD59x18 x) pure returns (SD1x18 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < uMIN_SD1x18) {\n        revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Underflow(x);\n    }\n    if (xInt > uMAX_SD1x18) {\n        revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Overflow(x);\n    }\n    result = SD1x18.wrap(int64(xInt));\n}\n\n/// @notice Casts an SD59x18 number into SD21x18.\n/// @dev Requirements:\n/// - x ≥ uMIN_SD21x18\n/// - x ≤ uMAX_SD21x18\nfunction intoSD21x18(SD59x18 x) pure returns (SD21x18 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < uMIN_SD21x18) {\n        revert CastingErrors.PRBMath_SD59x18_IntoSD21x18_Underflow(x);\n    }\n    if (xInt > uMAX_SD21x18) {\n        revert CastingErrors.PRBMath_SD59x18_IntoSD21x18_Overflow(x);\n    }\n    result = SD21x18.wrap(int128(xInt));\n}\n\n/// @notice Casts an SD59x18 number into UD2x18.\n/// @dev Requirements:\n/// - x ≥ 0\n/// - x ≤ uMAX_UD2x18\nfunction intoUD2x18(SD59x18 x) pure returns (UD2x18 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Underflow(x);\n    }\n    if (xInt > int256(uint256(uMAX_UD2x18))) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Overflow(x);\n    }\n    result = UD2x18.wrap(uint64(uint256(xInt)));\n}\n\n/// @notice Casts an SD59x18 number into UD21x18.\n/// @dev Requirements:\n/// - x ≥ 0\n/// - x ≤ uMAX_UD21x18\nfunction intoUD21x18(SD59x18 x) pure returns (UD21x18 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUD21x18_Underflow(x);\n    }\n    if (xInt > int256(uint256(uMAX_UD21x18))) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUD21x18_Overflow(x);\n    }\n    result = UD21x18.wrap(uint128(uint256(xInt)));\n}\n\n/// @notice Casts an SD59x18 number into UD60x18.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUD60x18(SD59x18 x) pure returns (UD60x18 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUD60x18_Underflow(x);\n    }\n    result = UD60x18.wrap(uint256(xInt));\n}\n\n/// @notice Casts an SD59x18 number into uint256.\n/// @dev Requirements:\n/// - x ≥ 0\nfunction intoUint256(SD59x18 x) pure returns (uint256 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUint256_Underflow(x);\n    }\n    result = uint256(xInt);\n}\n\n/// @notice Casts an SD59x18 number into uint128.\n/// @dev Requirements:\n/// - x ≥ 0\n/// - x ≤ uMAX_UINT128\nfunction intoUint128(SD59x18 x) pure returns (uint128 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUint128_Underflow(x);\n    }\n    if (xInt > int256(uint256(MAX_UINT128))) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUint128_Overflow(x);\n    }\n    result = uint128(uint256(xInt));\n}\n\n/// @notice Casts an SD59x18 number into uint40.\n/// @dev Requirements:\n/// - x ≥ 0\n/// - x ≤ MAX_UINT40\nfunction intoUint40(SD59x18 x) pure returns (uint40 result) {\n    int256 xInt = SD59x18.unwrap(x);\n    if (xInt < 0) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUint40_Underflow(x);\n    }\n    if (xInt > int256(uint256(MAX_UINT40))) {\n        revert CastingErrors.PRBMath_SD59x18_IntoUint40_Overflow(x);\n    }\n    result = uint40(uint256(xInt));\n}\n\n/// @notice Alias for {wrap}.\nfunction sd(int256 x) pure returns (SD59x18 result) {\n    result = SD59x18.wrap(x);\n}\n\n/// @notice Alias for {wrap}.\nfunction sd59x18(int256 x) pure returns (SD59x18 result) {\n    result = SD59x18.wrap(x);\n}\n\n/// @notice Unwraps an SD59x18 number into int256.\nfunction unwrap(SD59x18 x) pure returns (int256 result) {\n    result = SD59x18.unwrap(x);\n}\n\n/// @notice Wraps an int256 number into SD59x18.\nfunction wrap(int256 x) pure returns (SD59x18 result) {\n    result = SD59x18.wrap(x);\n}\n"
  },
  {
    "path": "src/sd59x18/Constants.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { SD59x18 } from \"./ValueType.sol\";\n\n// NOTICE: the \"u\" prefix stands for \"unwrapped\".\n\n/// @dev Euler's number as an SD59x18 number.\nSD59x18 constant E = SD59x18.wrap(2_718281828459045235);\n\n/// @dev The maximum input permitted in {exp}.\nint256 constant uEXP_MAX_INPUT = 133_084258667509499440;\nSD59x18 constant EXP_MAX_INPUT = SD59x18.wrap(uEXP_MAX_INPUT);\n\n/// @dev Any value less than this returns 0 in {exp}.\nint256 constant uEXP_MIN_THRESHOLD = -41_446531673892822322;\nSD59x18 constant EXP_MIN_THRESHOLD = SD59x18.wrap(uEXP_MIN_THRESHOLD);\n\n/// @dev The maximum input permitted in {exp2}.\nint256 constant uEXP2_MAX_INPUT = 192e18 - 1;\nSD59x18 constant EXP2_MAX_INPUT = SD59x18.wrap(uEXP2_MAX_INPUT);\n\n/// @dev Any value less than this returns 0 in {exp2}.\nint256 constant uEXP2_MIN_THRESHOLD = -59_794705707972522261;\nSD59x18 constant EXP2_MIN_THRESHOLD = SD59x18.wrap(uEXP2_MIN_THRESHOLD);\n\n/// @dev Half the UNIT number.\nint256 constant uHALF_UNIT = 0.5e18;\nSD59x18 constant HALF_UNIT = SD59x18.wrap(uHALF_UNIT);\n\n/// @dev $log_2(10)$ as an SD59x18 number.\nint256 constant uLOG2_10 = 3_321928094887362347;\nSD59x18 constant LOG2_10 = SD59x18.wrap(uLOG2_10);\n\n/// @dev $log_2(e)$ as an SD59x18 number.\nint256 constant uLOG2_E = 1_442695040888963407;\nSD59x18 constant LOG2_E = SD59x18.wrap(uLOG2_E);\n\n/// @dev The maximum value an SD59x18 number can have.\nint256 constant uMAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967;\nSD59x18 constant MAX_SD59x18 = SD59x18.wrap(uMAX_SD59x18);\n\n/// @dev The maximum whole value an SD59x18 number can have.\nint256 constant uMAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000;\nSD59x18 constant MAX_WHOLE_SD59x18 = SD59x18.wrap(uMAX_WHOLE_SD59x18);\n\n/// @dev The minimum value an SD59x18 number can have.\nint256 constant uMIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968;\nSD59x18 constant MIN_SD59x18 = SD59x18.wrap(uMIN_SD59x18);\n\n/// @dev The minimum whole value an SD59x18 number can have.\nint256 constant uMIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000;\nSD59x18 constant MIN_WHOLE_SD59x18 = SD59x18.wrap(uMIN_WHOLE_SD59x18);\n\n/// @dev PI as an SD59x18 number.\nSD59x18 constant PI = SD59x18.wrap(3_141592653589793238);\n\n/// @dev The unit number, which gives the decimal precision of SD59x18.\nint256 constant uUNIT = 1e18;\nSD59x18 constant UNIT = SD59x18.wrap(1e18);\n\n/// @dev The unit number squared.\nint256 constant uUNIT_SQUARED = 1e36;\nSD59x18 constant UNIT_SQUARED = SD59x18.wrap(uUNIT_SQUARED);\n\n/// @dev Zero as an SD59x18 number.\nSD59x18 constant ZERO = SD59x18.wrap(0);\n"
  },
  {
    "path": "src/sd59x18/Conversions.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { uMAX_SD59x18, uMIN_SD59x18, uUNIT } from \"./Constants.sol\";\nimport { PRBMath_SD59x18_Convert_Overflow, PRBMath_SD59x18_Convert_Underflow } from \"./Errors.sol\";\nimport { SD59x18 } from \"./ValueType.sol\";\n\n/// @notice Converts a simple integer to SD59x18 by multiplying it by `UNIT`.\n///\n/// @dev Requirements:\n/// - x ≥ `MIN_SD59x18 / UNIT`\n/// - x ≤ `MAX_SD59x18 / UNIT`\n///\n/// @param x The basic integer to convert.\n/// @return result The same number converted to SD59x18.\nfunction convert(int256 x) pure returns (SD59x18 result) {\n    if (x < uMIN_SD59x18 / uUNIT) {\n        revert PRBMath_SD59x18_Convert_Underflow(x);\n    }\n    if (x > uMAX_SD59x18 / uUNIT) {\n        revert PRBMath_SD59x18_Convert_Overflow(x);\n    }\n    unchecked {\n        result = SD59x18.wrap(x * uUNIT);\n    }\n}\n\n/// @notice Converts an SD59x18 number to a simple integer by dividing it by `UNIT`.\n/// @dev The result is rounded toward zero.\n/// @param x The SD59x18 number to convert.\n/// @return result The same number as a simple integer.\nfunction convert(SD59x18 x) pure returns (int256 result) {\n    result = SD59x18.unwrap(x) / uUNIT;\n}\n"
  },
  {
    "path": "src/sd59x18/Errors.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { SD59x18 } from \"./ValueType.sol\";\n\n/// @notice Thrown when taking the absolute value of `MIN_SD59x18`.\nerror PRBMath_SD59x18_Abs_MinSD59x18();\n\n/// @notice Thrown when ceiling a number overflows SD59x18.\nerror PRBMath_SD59x18_Ceil_Overflow(SD59x18 x);\n\n/// @notice Thrown when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMath_SD59x18_Convert_Overflow(int256 x);\n\n/// @notice Thrown when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMath_SD59x18_Convert_Underflow(int256 x);\n\n/// @notice Thrown when dividing two numbers and one of them is `MIN_SD59x18`.\nerror PRBMath_SD59x18_Div_InputTooSmall();\n\n/// @notice Thrown when dividing two numbers and one of the intermediary unsigned results overflows SD59x18.\nerror PRBMath_SD59x18_Div_Overflow(SD59x18 x, SD59x18 y);\n\n/// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441.\nerror PRBMath_SD59x18_Exp_InputTooBig(SD59x18 x);\n\n/// @notice Thrown when taking the binary exponent of a base greater than 192e18.\nerror PRBMath_SD59x18_Exp2_InputTooBig(SD59x18 x);\n\n/// @notice Thrown when flooring a number underflows SD59x18.\nerror PRBMath_SD59x18_Floor_Underflow(SD59x18 x);\n\n/// @notice Thrown when taking the geometric mean of two numbers and their product is negative.\nerror PRBMath_SD59x18_Gm_NegativeProduct(SD59x18 x, SD59x18 y);\n\n/// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows SD59x18.\nerror PRBMath_SD59x18_Gm_Overflow(SD59x18 x, SD59x18 y);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD1x18.\nerror PRBMath_SD59x18_IntoSD1x18_Overflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD1x18.\nerror PRBMath_SD59x18_IntoSD1x18_Underflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD21x18.\nerror PRBMath_SD59x18_IntoSD21x18_Overflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD21x18.\nerror PRBMath_SD59x18_IntoSD21x18_Underflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD2x18.\nerror PRBMath_SD59x18_IntoUD2x18_Overflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD2x18.\nerror PRBMath_SD59x18_IntoUD2x18_Underflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD21x18.\nerror PRBMath_SD59x18_IntoUD21x18_Overflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD21x18.\nerror PRBMath_SD59x18_IntoUD21x18_Underflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD60x18.\nerror PRBMath_SD59x18_IntoUD60x18_Underflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint128.\nerror PRBMath_SD59x18_IntoUint128_Overflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint128.\nerror PRBMath_SD59x18_IntoUint128_Underflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint256.\nerror PRBMath_SD59x18_IntoUint256_Underflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint40.\nerror PRBMath_SD59x18_IntoUint40_Overflow(SD59x18 x);\n\n/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint40.\nerror PRBMath_SD59x18_IntoUint40_Underflow(SD59x18 x);\n\n/// @notice Thrown when taking the logarithm of a number less than or equal to zero.\nerror PRBMath_SD59x18_Log_InputTooSmall(SD59x18 x);\n\n/// @notice Thrown when multiplying two numbers and one of the inputs is `MIN_SD59x18`.\nerror PRBMath_SD59x18_Mul_InputTooSmall();\n\n/// @notice Thrown when multiplying two numbers and the intermediary absolute result overflows SD59x18.\nerror PRBMath_SD59x18_Mul_Overflow(SD59x18 x, SD59x18 y);\n\n/// @notice Thrown when raising a number to a power and the intermediary absolute result overflows SD59x18.\nerror PRBMath_SD59x18_Powu_Overflow(SD59x18 x, uint256 y);\n\n/// @notice Thrown when taking the square root of a negative number.\nerror PRBMath_SD59x18_Sqrt_NegativeInput(SD59x18 x);\n\n/// @notice Thrown when calculating the square root overflows SD59x18.\nerror PRBMath_SD59x18_Sqrt_Overflow(SD59x18 x);\n"
  },
  {
    "path": "src/sd59x18/Helpers.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { wrap } from \"./Casting.sol\";\nimport { SD59x18 } from \"./ValueType.sol\";\n\n/// @notice Implements the checked addition operation (+) in the SD59x18 type.\nfunction add(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    return wrap(x.unwrap() + y.unwrap());\n}\n\n/// @notice Implements the AND (&) bitwise operation in the SD59x18 type.\nfunction and(SD59x18 x, int256 bits) pure returns (SD59x18 result) {\n    return wrap(x.unwrap() & bits);\n}\n\n/// @notice Implements the AND (&) bitwise operation in the SD59x18 type.\nfunction and2(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    return wrap(x.unwrap() & y.unwrap());\n}\n\n/// @notice Implements the equal (=) operation in the SD59x18 type.\nfunction eq(SD59x18 x, SD59x18 y) pure returns (bool result) {\n    result = x.unwrap() == y.unwrap();\n}\n\n/// @notice Implements the greater than operation (>) in the SD59x18 type.\nfunction gt(SD59x18 x, SD59x18 y) pure returns (bool result) {\n    result = x.unwrap() > y.unwrap();\n}\n\n/// @notice Implements the greater than or equal to operation (>=) in the SD59x18 type.\nfunction gte(SD59x18 x, SD59x18 y) pure returns (bool result) {\n    result = x.unwrap() >= y.unwrap();\n}\n\n/// @notice Implements a zero comparison check function in the SD59x18 type.\nfunction isZero(SD59x18 x) pure returns (bool result) {\n    result = x.unwrap() == 0;\n}\n\n/// @notice Implements the left shift operation (<<) in the SD59x18 type.\nfunction lshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {\n    result = wrap(x.unwrap() << bits);\n}\n\n/// @notice Implements the lower than operation (<) in the SD59x18 type.\nfunction lt(SD59x18 x, SD59x18 y) pure returns (bool result) {\n    result = x.unwrap() < y.unwrap();\n}\n\n/// @notice Implements the lower than or equal to operation (<=) in the SD59x18 type.\nfunction lte(SD59x18 x, SD59x18 y) pure returns (bool result) {\n    result = x.unwrap() <= y.unwrap();\n}\n\n/// @notice Implements the unchecked modulo operation (%) in the SD59x18 type.\nfunction mod(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    result = wrap(x.unwrap() % y.unwrap());\n}\n\n/// @notice Implements the not equal operation (!=) in the SD59x18 type.\nfunction neq(SD59x18 x, SD59x18 y) pure returns (bool result) {\n    result = x.unwrap() != y.unwrap();\n}\n\n/// @notice Implements the NOT (~) bitwise operation in the SD59x18 type.\nfunction not(SD59x18 x) pure returns (SD59x18 result) {\n    result = wrap(~x.unwrap());\n}\n\n/// @notice Implements the OR (|) bitwise operation in the SD59x18 type.\nfunction or(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    result = wrap(x.unwrap() | y.unwrap());\n}\n\n/// @notice Implements the right shift operation (>>) in the SD59x18 type.\nfunction rshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {\n    result = wrap(x.unwrap() >> bits);\n}\n\n/// @notice Implements the checked subtraction operation (-) in the SD59x18 type.\nfunction sub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    result = wrap(x.unwrap() - y.unwrap());\n}\n\n/// @notice Implements the checked unary minus operation (-) in the SD59x18 type.\nfunction unary(SD59x18 x) pure returns (SD59x18 result) {\n    result = wrap(-x.unwrap());\n}\n\n/// @notice Implements the unchecked addition operation (+) in the SD59x18 type.\nfunction uncheckedAdd(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    unchecked {\n        result = wrap(x.unwrap() + y.unwrap());\n    }\n}\n\n/// @notice Implements the unchecked subtraction operation (-) in the SD59x18 type.\nfunction uncheckedSub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    unchecked {\n        result = wrap(x.unwrap() - y.unwrap());\n    }\n}\n\n/// @notice Implements the unchecked unary minus operation (-) in the SD59x18 type.\nfunction uncheckedUnary(SD59x18 x) pure returns (SD59x18 result) {\n    unchecked {\n        result = wrap(-x.unwrap());\n    }\n}\n\n/// @notice Implements the XOR (^) bitwise operation in the SD59x18 type.\nfunction xor(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    result = wrap(x.unwrap() ^ y.unwrap());\n}\n"
  },
  {
    "path": "src/sd59x18/Math.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"../Common.sol\" as Common;\nimport \"./Errors.sol\" as Errors;\nimport {\n    uEXP_MAX_INPUT,\n    uEXP2_MAX_INPUT,\n    uEXP_MIN_THRESHOLD,\n    uEXP2_MIN_THRESHOLD,\n    uHALF_UNIT,\n    uLOG2_10,\n    uLOG2_E,\n    uMAX_SD59x18,\n    uMAX_WHOLE_SD59x18,\n    uMIN_SD59x18,\n    uMIN_WHOLE_SD59x18,\n    UNIT,\n    uUNIT,\n    uUNIT_SQUARED,\n    ZERO\n} from \"./Constants.sol\";\nimport { wrap } from \"./Helpers.sol\";\nimport { SD59x18 } from \"./ValueType.sol\";\n\n/// @notice Calculates the absolute value of x.\n///\n/// @dev Requirements:\n/// - x > MIN_SD59x18.\n///\n/// @param x The SD59x18 number for which to calculate the absolute value.\n/// @return result The absolute value of x as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction abs(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    if (xInt == uMIN_SD59x18) {\n        revert Errors.PRBMath_SD59x18_Abs_MinSD59x18();\n    }\n    result = xInt < 0 ? wrap(-xInt) : x;\n}\n\n/// @notice Calculates the arithmetic average of x and y.\n///\n/// @dev Notes:\n/// - The result is rounded toward zero.\n///\n/// @param x The first operand as an SD59x18 number.\n/// @param y The second operand as an SD59x18 number.\n/// @return result The arithmetic average as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction avg(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    int256 yInt = y.unwrap();\n\n    unchecked {\n        // This operation is equivalent to `x / 2 +  y / 2`, and it can never overflow.\n        int256 sum = (xInt >> 1) + (yInt >> 1);\n\n        if (sum < 0) {\n            // If at least one of x and y is odd, add 1 to the result, because shifting negative numbers to the right\n            // rounds toward negative infinity. The right part is equivalent to `sum + (x % 2 == 1 || y % 2 == 1)`.\n            assembly (\"memory-safe\") {\n                result := add(sum, and(or(xInt, yInt), 1))\n            }\n        } else {\n            // Add 1 if both x and y are odd to account for the double 0.5 remainder truncated after shifting.\n            result = wrap(sum + (xInt & yInt & 1));\n        }\n    }\n}\n\n/// @notice Yields the smallest whole number greater than or equal to x.\n///\n/// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts.\n/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n///\n/// Requirements:\n/// - x ≤ MAX_WHOLE_SD59x18\n///\n/// @param x The SD59x18 number to ceil.\n/// @return result The smallest whole number greater than or equal to x, as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction ceil(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    if (xInt > uMAX_WHOLE_SD59x18) {\n        revert Errors.PRBMath_SD59x18_Ceil_Overflow(x);\n    }\n\n    int256 remainder = xInt % uUNIT;\n    if (remainder == 0) {\n        result = x;\n    } else {\n        unchecked {\n            // Solidity uses C fmod style, which returns a modulus with the same sign as x.\n            int256 resultInt = xInt - remainder;\n            if (xInt > 0) {\n                resultInt += uUNIT;\n            }\n            result = wrap(resultInt);\n        }\n    }\n}\n\n/// @notice Divides two SD59x18 numbers, returning a new SD59x18 number.\n///\n/// @dev This is an extension of {Common.mulDiv} for signed numbers, which works by computing the signs and the absolute\n/// values separately.\n///\n/// Notes:\n/// - Refer to the notes in {Common.mulDiv}.\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - Refer to the requirements in {Common.mulDiv}.\n/// - None of the inputs can be `MIN_SD59x18`.\n/// - The denominator must not be zero.\n/// - The result must fit in SD59x18.\n///\n/// @param x The numerator as an SD59x18 number.\n/// @param y The denominator as an SD59x18 number.\n/// @return result The quotient as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction div(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    int256 yInt = y.unwrap();\n    if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {\n        revert Errors.PRBMath_SD59x18_Div_InputTooSmall();\n    }\n\n    // Get hold of the absolute values of x and y.\n    uint256 xAbs;\n    uint256 yAbs;\n    unchecked {\n        xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);\n        yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);\n    }\n\n    // Compute the absolute value (x*UNIT÷y). The resulting value must fit in SD59x18.\n    uint256 resultAbs = Common.mulDiv(xAbs, uint256(uUNIT), yAbs);\n    if (resultAbs > uint256(uMAX_SD59x18)) {\n        revert Errors.PRBMath_SD59x18_Div_Overflow(x, y);\n    }\n\n    // Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for\n    // negative, 0 for positive or zero).\n    bool sameSign = (xInt ^ yInt) > -1;\n\n    // If the inputs have the same sign, the result should be positive. Otherwise, it should be negative.\n    unchecked {\n        result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));\n    }\n}\n\n/// @notice Calculates the natural exponent of x using the following formula:\n///\n/// $$\n/// e^x = 2^{x * log_2{e}}\n/// $$\n///\n/// @dev Notes:\n/// - Refer to the notes in {exp2}.\n///\n/// Requirements:\n/// - Refer to the requirements in {exp2}.\n/// - x < 133_084258667509499441.\n///\n/// @param x The exponent as an SD59x18 number.\n/// @return result The result as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction exp(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n\n    // Any input less than the threshold returns zero.\n    // This check also prevents an overflow for very small numbers.\n    if (xInt < uEXP_MIN_THRESHOLD) {\n        return ZERO;\n    }\n\n    // This check prevents values greater than 192e18 from being passed to {exp2}.\n    if (xInt > uEXP_MAX_INPUT) {\n        revert Errors.PRBMath_SD59x18_Exp_InputTooBig(x);\n    }\n\n    unchecked {\n        // Inline the fixed-point multiplication to save gas.\n        int256 doubleUnitProduct = xInt * uLOG2_E;\n        result = exp2(wrap(doubleUnitProduct / uUNIT));\n    }\n}\n\n/// @notice Calculates the binary exponent of x using the binary fraction method using the following formula:\n///\n/// $$\n/// 2^{-x} = \\frac{1}{2^x}\n/// $$\n///\n/// @dev See https://ethereum.stackexchange.com/q/79903/24693.\n///\n/// Notes:\n/// - If x < -59_794705707972522261, the result is zero.\n///\n/// Requirements:\n/// - x < 192e18.\n/// - The result must fit in SD59x18.\n///\n/// @param x The exponent as an SD59x18 number.\n/// @return result The result as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction exp2(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    if (xInt < 0) {\n        // The inverse of any number less than the threshold is truncated to zero.\n        if (xInt < uEXP2_MIN_THRESHOLD) {\n            return ZERO;\n        }\n\n        unchecked {\n            // Inline the fixed-point inversion to save gas.\n            result = wrap(uUNIT_SQUARED / exp2(wrap(-xInt)).unwrap());\n        }\n    } else {\n        // Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format.\n        if (xInt > uEXP2_MAX_INPUT) {\n            revert Errors.PRBMath_SD59x18_Exp2_InputTooBig(x);\n        }\n\n        unchecked {\n            // Convert x to the 192.64-bit fixed-point format.\n            uint256 x_192x64 = uint256((xInt << 64) / uUNIT);\n\n            // It is safe to cast the result to int256 due to the checks above.\n            result = wrap(int256(Common.exp2(x_192x64)));\n        }\n    }\n}\n\n/// @notice Yields the greatest whole number less than or equal to x.\n///\n/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional\n/// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n///\n/// Requirements:\n/// - x ≥ MIN_WHOLE_SD59x18\n///\n/// @param x The SD59x18 number to floor.\n/// @return result The greatest whole number less than or equal to x, as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction floor(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    if (xInt < uMIN_WHOLE_SD59x18) {\n        revert Errors.PRBMath_SD59x18_Floor_Underflow(x);\n    }\n\n    int256 remainder = xInt % uUNIT;\n    if (remainder == 0) {\n        result = x;\n    } else {\n        unchecked {\n            // Solidity uses C fmod style, which returns a modulus with the same sign as x.\n            int256 resultInt = xInt - remainder;\n            if (xInt < 0) {\n                resultInt -= uUNIT;\n            }\n            result = wrap(resultInt);\n        }\n    }\n}\n\n/// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right.\n/// of the radix point for negative numbers.\n/// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part\n/// @param x The SD59x18 number to get the fractional part of.\n/// @return result The fractional part of x as an SD59x18 number.\nfunction frac(SD59x18 x) pure returns (SD59x18 result) {\n    result = wrap(x.unwrap() % uUNIT);\n}\n\n/// @notice Calculates the geometric mean of x and y, i.e. $\\sqrt{x * y}$.\n///\n/// @dev Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - x * y must fit in SD59x18.\n/// - x * y must not be negative, since complex numbers are not supported.\n///\n/// @param x The first operand as an SD59x18 number.\n/// @param y The second operand as an SD59x18 number.\n/// @return result The result as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction gm(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    int256 yInt = y.unwrap();\n    if (xInt == 0 || yInt == 0) {\n        return ZERO;\n    }\n\n    unchecked {\n        // Equivalent to `xy / x != y`. Checking for overflow this way is faster than letting Solidity do it.\n        int256 xyInt = xInt * yInt;\n        if (xyInt / xInt != yInt) {\n            revert Errors.PRBMath_SD59x18_Gm_Overflow(x, y);\n        }\n\n        // The product must not be negative, since complex numbers are not supported.\n        if (xyInt < 0) {\n            revert Errors.PRBMath_SD59x18_Gm_NegativeProduct(x, y);\n        }\n\n        // We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT`\n        // during multiplication. See the comments in {Common.sqrt}.\n        uint256 resultUint = Common.sqrt(uint256(xyInt));\n        result = wrap(int256(resultUint));\n    }\n}\n\n/// @notice Calculates the inverse of x.\n///\n/// @dev Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - x must not be zero.\n///\n/// @param x The SD59x18 number for which to calculate the inverse.\n/// @return result The inverse as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction inv(SD59x18 x) pure returns (SD59x18 result) {\n    result = wrap(uUNIT_SQUARED / x.unwrap());\n}\n\n/// @notice Calculates the natural logarithm of x using the following formula:\n///\n/// $$\n/// ln{x} = log_2{x} / log_2{e}\n/// $$\n///\n/// @dev Notes:\n/// - Refer to the notes in {log2}.\n/// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`.\n///\n/// Requirements:\n/// - Refer to the requirements in {log2}.\n///\n/// @param x The SD59x18 number for which to calculate the natural logarithm.\n/// @return result The natural logarithm as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction ln(SD59x18 x) pure returns (SD59x18 result) {\n    // Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that\n    // {log2} can return is ~195_205294292027477728.\n    result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E);\n}\n\n/// @notice Calculates the common logarithm of x using the following formula:\n///\n/// $$\n/// log_{10}{x} = log_2{x} / log_2{10}\n/// $$\n///\n/// However, if x is an exact power of ten, a hard coded value is returned.\n///\n/// @dev Notes:\n/// - Refer to the notes in {log2}.\n///\n/// Requirements:\n/// - Refer to the requirements in {log2}.\n///\n/// @param x The SD59x18 number for which to calculate the common logarithm.\n/// @return result The common logarithm as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction log10(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    if (xInt < 0) {\n        revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x);\n    }\n\n    // Note that the `mul` in this block is the standard multiplication operation, not {SD59x18.mul}.\n    // prettier-ignore\n    assembly (\"memory-safe\") {\n        switch x\n        case 1 { result := mul(uUNIT, sub(0, 18)) }\n        case 10 { result := mul(uUNIT, sub(1, 18)) }\n        case 100 { result := mul(uUNIT, sub(2, 18)) }\n        case 1000 { result := mul(uUNIT, sub(3, 18)) }\n        case 10000 { result := mul(uUNIT, sub(4, 18)) }\n        case 100000 { result := mul(uUNIT, sub(5, 18)) }\n        case 1000000 { result := mul(uUNIT, sub(6, 18)) }\n        case 10000000 { result := mul(uUNIT, sub(7, 18)) }\n        case 100000000 { result := mul(uUNIT, sub(8, 18)) }\n        case 1000000000 { result := mul(uUNIT, sub(9, 18)) }\n        case 10000000000 { result := mul(uUNIT, sub(10, 18)) }\n        case 100000000000 { result := mul(uUNIT, sub(11, 18)) }\n        case 1000000000000 { result := mul(uUNIT, sub(12, 18)) }\n        case 10000000000000 { result := mul(uUNIT, sub(13, 18)) }\n        case 100000000000000 { result := mul(uUNIT, sub(14, 18)) }\n        case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) }\n        case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) }\n        case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) }\n        case 1000000000000000000 { result := 0 }\n        case 10000000000000000000 { result := uUNIT }\n        case 100000000000000000000 { result := mul(uUNIT, 2) }\n        case 1000000000000000000000 { result := mul(uUNIT, 3) }\n        case 10000000000000000000000 { result := mul(uUNIT, 4) }\n        case 100000000000000000000000 { result := mul(uUNIT, 5) }\n        case 1000000000000000000000000 { result := mul(uUNIT, 6) }\n        case 10000000000000000000000000 { result := mul(uUNIT, 7) }\n        case 100000000000000000000000000 { result := mul(uUNIT, 8) }\n        case 1000000000000000000000000000 { result := mul(uUNIT, 9) }\n        case 10000000000000000000000000000 { result := mul(uUNIT, 10) }\n        case 100000000000000000000000000000 { result := mul(uUNIT, 11) }\n        case 1000000000000000000000000000000 { result := mul(uUNIT, 12) }\n        case 10000000000000000000000000000000 { result := mul(uUNIT, 13) }\n        case 100000000000000000000000000000000 { result := mul(uUNIT, 14) }\n        case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) }\n        case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) }\n        case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) }\n        case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) }\n        case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) }\n        case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) }\n        case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) }\n        case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) }\n        case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) }\n        case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) }\n        case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) }\n        case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) }\n        case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) }\n        case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) }\n        case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) }\n        case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) }\n        case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) }\n        case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) }\n        case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) }\n        case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) }\n        case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) }\n        case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) }\n        case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) }\n        case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) }\n        case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) }\n        case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) }\n        case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) }\n        case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) }\n        case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) }\n        case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) }\n        case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) }\n        case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) }\n        case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) }\n        case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) }\n        case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) }\n        case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) }\n        default { result := uMAX_SD59x18 }\n    }\n\n    if (result.unwrap() == uMAX_SD59x18) {\n        unchecked {\n            // Inline the fixed-point division to save gas.\n            result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10);\n        }\n    }\n}\n\n/// @notice Calculates the binary logarithm of x using the iterative approximation algorithm:\n///\n/// $$\n/// log_2{x} = n + log_2{y}, \\text{ where } y = x*2^{-n}, \\ y \\in [1, 2)\n/// $$\n///\n/// For $0 \\leq x \\lt 1$, the input is inverted:\n///\n/// $$\n/// log_2{x} = -log_2{\\frac{1}{x}}\n/// $$\n///\n/// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation.\n///\n/// Notes:\n/// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal.\n///\n/// Requirements:\n/// - x > 0\n///\n/// @param x The SD59x18 number for which to calculate the binary logarithm.\n/// @return result The binary logarithm as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction log2(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    if (xInt <= 0) {\n        revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x);\n    }\n\n    unchecked {\n        int256 sign;\n        if (xInt >= uUNIT) {\n            sign = 1;\n        } else {\n            sign = -1;\n            // Inline the fixed-point inversion to save gas.\n            xInt = uUNIT_SQUARED / xInt;\n        }\n\n        // Calculate the integer part of the logarithm.\n        uint256 n = Common.msb(uint256(xInt / uUNIT));\n\n        // This is the integer part of the logarithm as an SD59x18 number. The operation can't overflow\n        // because n is at most 255, `UNIT` is 1e18, and the sign is either 1 or -1.\n        int256 resultInt = int256(n) * uUNIT;\n\n        // Calculate $y = x * 2^{-n}$.\n        int256 y = xInt >> n;\n\n        // If y is the unit number, the fractional part is zero.\n        if (y == uUNIT) {\n            return wrap(resultInt * sign);\n        }\n\n        // Calculate the fractional part via the iterative approximation.\n        // The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient.\n        int256 doubleUnit = 2e18;\n        for (int256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {\n            y = (y * y) / uUNIT;\n\n            // Is y^2 >= 2e18 and so in the range [2e18, 4e18)?\n            if (y >= doubleUnit) {\n                // Add the 2^{-m} factor to the logarithm.\n                resultInt = resultInt + delta;\n\n                // Halve y, which corresponds to z/2 in the Wikipedia article.\n                y >>= 1;\n            }\n        }\n        resultInt *= sign;\n        result = wrap(resultInt);\n    }\n}\n\n/// @notice Multiplies two SD59x18 numbers together, returning a new SD59x18 number.\n///\n/// @dev Notes:\n/// - Refer to the notes in {Common.mulDiv18}.\n///\n/// Requirements:\n/// - Refer to the requirements in {Common.mulDiv18}.\n/// - None of the inputs can be `MIN_SD59x18`.\n/// - The result must fit in SD59x18.\n///\n/// @param x The multiplicand as an SD59x18 number.\n/// @param y The multiplier as an SD59x18 number.\n/// @return result The product as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction mul(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    int256 yInt = y.unwrap();\n    if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {\n        revert Errors.PRBMath_SD59x18_Mul_InputTooSmall();\n    }\n\n    // Get hold of the absolute values of x and y.\n    uint256 xAbs;\n    uint256 yAbs;\n    unchecked {\n        xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);\n        yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);\n    }\n\n    // Compute the absolute value (x*y÷UNIT). The resulting value must fit in SD59x18.\n    uint256 resultAbs = Common.mulDiv18(xAbs, yAbs);\n    if (resultAbs > uint256(uMAX_SD59x18)) {\n        revert Errors.PRBMath_SD59x18_Mul_Overflow(x, y);\n    }\n\n    // Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for\n    // negative, 0 for positive or zero).\n    bool sameSign = (xInt ^ yInt) > -1;\n\n    // If the inputs have the same sign, the result should be positive. Otherwise, it should be negative.\n    unchecked {\n        result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));\n    }\n}\n\n/// @notice Raises x to the power of y using the following formula:\n///\n/// $$\n/// x^y = 2^{log_2{x} * y}\n/// $$\n///\n/// @dev Notes:\n/// - Refer to the notes in {exp2}, {log2}, and {mul}.\n/// - Returns `UNIT` for 0^0.\n///\n/// Requirements:\n/// - Refer to the requirements in {exp2}, {log2}, and {mul}.\n///\n/// @param x The base as an SD59x18 number.\n/// @param y Exponent to raise x to, as an SD59x18 number\n/// @return result x raised to power y, as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    int256 yInt = y.unwrap();\n\n    // If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero.\n    if (xInt == 0) {\n        return yInt == 0 ? UNIT : ZERO;\n    }\n    // If x is `UNIT`, the result is always `UNIT`.\n    else if (xInt == uUNIT) {\n        return UNIT;\n    }\n\n    // If y is zero, the result is always `UNIT`.\n    if (yInt == 0) {\n        return UNIT;\n    }\n    // If y is `UNIT`, the result is always x.\n    else if (yInt == uUNIT) {\n        return x;\n    }\n\n    // Calculate the result using the formula.\n    result = exp2(mul(log2(x), y));\n}\n\n/// @notice Raises x (an SD59x18 number) to the power y (an unsigned basic integer) using the well-known\n/// algorithm \"exponentiation by squaring\".\n///\n/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring.\n///\n/// Notes:\n/// - Refer to the notes in {Common.mulDiv18}.\n/// - Returns `UNIT` for 0^0.\n///\n/// Requirements:\n/// - Refer to the requirements in {abs} and {Common.mulDiv18}.\n/// - The result must fit in SD59x18.\n///\n/// @param x The base as an SD59x18 number.\n/// @param y The exponent as a uint256.\n/// @return result The result as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction powu(SD59x18 x, uint256 y) pure returns (SD59x18 result) {\n    uint256 xAbs = uint256(abs(x).unwrap());\n\n    // Calculate the first iteration of the loop in advance.\n    uint256 resultAbs = y & 1 > 0 ? xAbs : uint256(uUNIT);\n\n    // Equivalent to `for(y /= 2; y > 0; y /= 2)`.\n    uint256 yAux = y;\n    for (yAux >>= 1; yAux > 0; yAux >>= 1) {\n        xAbs = Common.mulDiv18(xAbs, xAbs);\n\n        // Equivalent to `y % 2 == 1`.\n        if (yAux & 1 > 0) {\n            resultAbs = Common.mulDiv18(resultAbs, xAbs);\n        }\n    }\n\n    // The result must fit in SD59x18.\n    if (resultAbs > uint256(uMAX_SD59x18)) {\n        revert Errors.PRBMath_SD59x18_Powu_Overflow(x, y);\n    }\n\n    unchecked {\n        // Is the base negative and the exponent odd? If yes, the result should be negative.\n        int256 resultInt = int256(resultAbs);\n        bool isNegative = x.unwrap() < 0 && y & 1 == 1;\n        if (isNegative) {\n            resultInt = -resultInt;\n        }\n        result = wrap(resultInt);\n    }\n}\n\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// Notes:\n/// - Only the positive root is returned.\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - x ≥ 0, since complex numbers are not supported.\n/// - x ≤ MAX_SD59x18 / UNIT\n///\n/// @param x The SD59x18 number for which to calculate the square root.\n/// @return result The result as an SD59x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction sqrt(SD59x18 x) pure returns (SD59x18 result) {\n    int256 xInt = x.unwrap();\n    if (xInt < 0) {\n        revert Errors.PRBMath_SD59x18_Sqrt_NegativeInput(x);\n    }\n    if (xInt > uMAX_SD59x18 / uUNIT) {\n        revert Errors.PRBMath_SD59x18_Sqrt_Overflow(x);\n    }\n\n    unchecked {\n        // Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two SD59x18 numbers.\n        // In this case, the two numbers are both the square root.\n        uint256 resultUint = Common.sqrt(uint256(xInt * uUNIT));\n        result = wrap(int256(resultUint));\n    }\n}\n"
  },
  {
    "path": "src/sd59x18/ValueType.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Casting.sol\" as Casting;\nimport \"./Helpers.sol\" as Helpers;\nimport \"./Math.sol\" as Math;\n\n/// @notice The signed 59.18-decimal fixed-point number representation, which can have up to 59 digits and up to 18\n/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity\n/// type int256.\ntype SD59x18 is int256;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CASTING\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Casting.intoInt256,\n    Casting.intoSD1x18,\n    Casting.intoSD21x18,\n    Casting.intoUD2x18,\n    Casting.intoUD21x18,\n    Casting.intoUD60x18,\n    Casting.intoUint256,\n    Casting.intoUint128,\n    Casting.intoUint40,\n    Casting.unwrap\n} for SD59x18 global;\n\n/*//////////////////////////////////////////////////////////////////////////\n                            MATHEMATICAL FUNCTIONS\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Math.abs,\n    Math.avg,\n    Math.ceil,\n    Math.div,\n    Math.exp,\n    Math.exp2,\n    Math.floor,\n    Math.frac,\n    Math.gm,\n    Math.inv,\n    Math.log10,\n    Math.log2,\n    Math.ln,\n    Math.mul,\n    Math.pow,\n    Math.powu,\n    Math.sqrt\n} for SD59x18 global;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                HELPER FUNCTIONS\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Helpers.add,\n    Helpers.and,\n    Helpers.eq,\n    Helpers.gt,\n    Helpers.gte,\n    Helpers.isZero,\n    Helpers.lshift,\n    Helpers.lt,\n    Helpers.lte,\n    Helpers.mod,\n    Helpers.neq,\n    Helpers.not,\n    Helpers.or,\n    Helpers.rshift,\n    Helpers.sub,\n    Helpers.uncheckedAdd,\n    Helpers.uncheckedSub,\n    Helpers.uncheckedUnary,\n    Helpers.xor\n} for SD59x18 global;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    OPERATORS\n//////////////////////////////////////////////////////////////////////////*/\n\n// The global \"using for\" directive makes it possible to use these operators on the SD59x18 type.\nusing {\n    Helpers.add as +,\n    Helpers.and2 as &,\n    Math.div as /,\n    Helpers.eq as ==,\n    Helpers.gt as >,\n    Helpers.gte as >=,\n    Helpers.lt as <,\n    Helpers.lte as <=,\n    Helpers.mod as %,\n    Math.mul as *,\n    Helpers.neq as !=,\n    Helpers.not as ~,\n    Helpers.or as |,\n    Helpers.sub as -,\n    Helpers.unary as -,\n    Helpers.xor as ^\n} for SD59x18 global;\n"
  },
  {
    "path": "src/ud21x18/Casting.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"../Common.sol\" as Common;\nimport \"./Errors.sol\" as Errors;\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\nimport { UD21x18 } from \"./ValueType.sol\";\n\n/// @notice Casts a UD21x18 number into SD59x18.\n/// @dev There is no overflow check because UD21x18 ⊆ SD59x18.\nfunction intoSD59x18(UD21x18 x) pure returns (SD59x18 result) {\n    result = SD59x18.wrap(int256(uint256(UD21x18.unwrap(x))));\n}\n\n/// @notice Casts a UD21x18 number into UD60x18.\n/// @dev There is no overflow check because UD21x18 ⊆ UD60x18.\nfunction intoUD60x18(UD21x18 x) pure returns (UD60x18 result) {\n    result = UD60x18.wrap(UD21x18.unwrap(x));\n}\n\n/// @notice Casts a UD21x18 number into uint128.\n/// @dev This is basically an alias for {unwrap}.\nfunction intoUint128(UD21x18 x) pure returns (uint128 result) {\n    result = UD21x18.unwrap(x);\n}\n\n/// @notice Casts a UD21x18 number into uint256.\n/// @dev There is no overflow check because UD21x18 ⊆ uint256.\nfunction intoUint256(UD21x18 x) pure returns (uint256 result) {\n    result = uint256(UD21x18.unwrap(x));\n}\n\n/// @notice Casts a UD21x18 number into uint40.\n/// @dev Requirements:\n/// - x ≤ MAX_UINT40\nfunction intoUint40(UD21x18 x) pure returns (uint40 result) {\n    uint128 xUint = UD21x18.unwrap(x);\n    if (xUint > uint128(Common.MAX_UINT40)) {\n        revert Errors.PRBMath_UD21x18_IntoUint40_Overflow(x);\n    }\n    result = uint40(xUint);\n}\n\n/// @notice Alias for {wrap}.\nfunction ud21x18(uint128 x) pure returns (UD21x18 result) {\n    result = UD21x18.wrap(x);\n}\n\n/// @notice Unwrap a UD21x18 number into uint128.\nfunction unwrap(UD21x18 x) pure returns (uint128 result) {\n    result = UD21x18.unwrap(x);\n}\n\n/// @notice Wraps a uint128 number into UD21x18.\nfunction wrap(uint128 x) pure returns (UD21x18 result) {\n    result = UD21x18.wrap(x);\n}\n"
  },
  {
    "path": "src/ud21x18/Constants.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { UD21x18 } from \"./ValueType.sol\";\n\n/// @dev Euler's number as a UD21x18 number.\nUD21x18 constant E = UD21x18.wrap(2_718281828459045235);\n\n/// @dev The maximum value a UD21x18 number can have.\nuint128 constant uMAX_UD21x18 = 340282366920938463463_374607431768211455;\nUD21x18 constant MAX_UD21x18 = UD21x18.wrap(uMAX_UD21x18);\n\n/// @dev PI as a UD21x18 number.\nUD21x18 constant PI = UD21x18.wrap(3_141592653589793238);\n\n/// @dev The unit number, which gives the decimal precision of UD21x18.\nuint256 constant uUNIT = 1e18;\nUD21x18 constant UNIT = UD21x18.wrap(1e18);\n"
  },
  {
    "path": "src/ud21x18/Errors.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { UD21x18 } from \"./ValueType.sol\";\n\n/// @notice Thrown when trying to cast a UD21x18 number that doesn't fit in uint40.\nerror PRBMath_UD21x18_IntoUint40_Overflow(UD21x18 x);\n"
  },
  {
    "path": "src/ud21x18/ValueType.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Casting.sol\" as Casting;\n\n/// @notice The unsigned 21.18-decimal fixed-point number representation, which can have up to 21 digits and up to 18\n/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity\n/// type uint128. This is useful when end users want to use uint128 to save gas, e.g. with tight variable packing in contract\n/// storage.\ntype UD21x18 is uint128;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CASTING\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Casting.intoSD59x18,\n    Casting.intoUD60x18,\n    Casting.intoUint128,\n    Casting.intoUint256,\n    Casting.intoUint40,\n    Casting.unwrap\n} for UD21x18 global;\n"
  },
  {
    "path": "src/ud2x18/Casting.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"../Common.sol\" as Common;\nimport \"./Errors.sol\" as Errors;\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { UD60x18 } from \"../ud60x18/ValueType.sol\";\nimport { UD2x18 } from \"./ValueType.sol\";\n\n/// @notice Casts a UD2x18 number into SD59x18.\n/// @dev There is no overflow check because UD2x18 ⊆ SD59x18.\nfunction intoSD59x18(UD2x18 x) pure returns (SD59x18 result) {\n    result = SD59x18.wrap(int256(uint256(UD2x18.unwrap(x))));\n}\n\n/// @notice Casts a UD2x18 number into UD60x18.\n/// @dev There is no overflow check because UD2x18 ⊆ UD60x18.\nfunction intoUD60x18(UD2x18 x) pure returns (UD60x18 result) {\n    result = UD60x18.wrap(UD2x18.unwrap(x));\n}\n\n/// @notice Casts a UD2x18 number into uint128.\n/// @dev There is no overflow check because UD2x18 ⊆ uint128.\nfunction intoUint128(UD2x18 x) pure returns (uint128 result) {\n    result = uint128(UD2x18.unwrap(x));\n}\n\n/// @notice Casts a UD2x18 number into uint256.\n/// @dev There is no overflow check because UD2x18 ⊆ uint256.\nfunction intoUint256(UD2x18 x) pure returns (uint256 result) {\n    result = uint256(UD2x18.unwrap(x));\n}\n\n/// @notice Casts a UD2x18 number into uint40.\n/// @dev Requirements:\n/// - x ≤ MAX_UINT40\nfunction intoUint40(UD2x18 x) pure returns (uint40 result) {\n    uint64 xUint = UD2x18.unwrap(x);\n    if (xUint > uint64(Common.MAX_UINT40)) {\n        revert Errors.PRBMath_UD2x18_IntoUint40_Overflow(x);\n    }\n    result = uint40(xUint);\n}\n\n/// @notice Alias for {wrap}.\nfunction ud2x18(uint64 x) pure returns (UD2x18 result) {\n    result = UD2x18.wrap(x);\n}\n\n/// @notice Unwrap a UD2x18 number into uint64.\nfunction unwrap(UD2x18 x) pure returns (uint64 result) {\n    result = UD2x18.unwrap(x);\n}\n\n/// @notice Wraps a uint64 number into UD2x18.\nfunction wrap(uint64 x) pure returns (UD2x18 result) {\n    result = UD2x18.wrap(x);\n}\n"
  },
  {
    "path": "src/ud2x18/Constants.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { UD2x18 } from \"./ValueType.sol\";\n\n/// @dev Euler's number as a UD2x18 number.\nUD2x18 constant E = UD2x18.wrap(2_718281828459045235);\n\n/// @dev The maximum value a UD2x18 number can have.\nuint64 constant uMAX_UD2x18 = 18_446744073709551615;\nUD2x18 constant MAX_UD2x18 = UD2x18.wrap(uMAX_UD2x18);\n\n/// @dev PI as a UD2x18 number.\nUD2x18 constant PI = UD2x18.wrap(3_141592653589793238);\n\n/// @dev The unit number, which gives the decimal precision of UD2x18.\nUD2x18 constant UNIT = UD2x18.wrap(1e18);\nuint64 constant uUNIT = 1e18;\n"
  },
  {
    "path": "src/ud2x18/Errors.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { UD2x18 } from \"./ValueType.sol\";\n\n/// @notice Thrown when trying to cast a UD2x18 number that doesn't fit in uint40.\nerror PRBMath_UD2x18_IntoUint40_Overflow(UD2x18 x);\n"
  },
  {
    "path": "src/ud2x18/ValueType.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Casting.sol\" as Casting;\n\n/// @notice The unsigned 2.18-decimal fixed-point number representation, which can have up to 2 digits and up to 18\n/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity\n/// type uint64. This is useful when end users want to use uint64 to save gas, e.g. with tight variable packing in contract\n/// storage.\ntype UD2x18 is uint64;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CASTING\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Casting.intoSD59x18,\n    Casting.intoUD60x18,\n    Casting.intoUint128,\n    Casting.intoUint256,\n    Casting.intoUint40,\n    Casting.unwrap\n} for UD2x18 global;\n"
  },
  {
    "path": "src/ud60x18/Casting.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Errors.sol\" as CastingErrors;\nimport { MAX_UINT128, MAX_UINT40 } from \"../Common.sol\";\nimport { uMAX_SD1x18 } from \"../sd1x18/Constants.sol\";\nimport { SD1x18 } from \"../sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18 } from \"../sd21x18/Constants.sol\";\nimport { SD21x18 } from \"../sd21x18/ValueType.sol\";\nimport { uMAX_SD59x18 } from \"../sd59x18/Constants.sol\";\nimport { SD59x18 } from \"../sd59x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"../ud2x18/Constants.sol\";\nimport { uMAX_UD21x18 } from \"../ud21x18/Constants.sol\";\nimport { UD2x18 } from \"../ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"../ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"./ValueType.sol\";\n\n/// @notice Casts a UD60x18 number into SD1x18.\n/// @dev Requirements:\n/// - x ≤ uMAX_SD1x18\nfunction intoSD1x18(UD60x18 x) pure returns (SD1x18 result) {\n    uint256 xUint = UD60x18.unwrap(x);\n    if (xUint > uint256(int256(uMAX_SD1x18))) {\n        revert CastingErrors.PRBMath_UD60x18_IntoSD1x18_Overflow(x);\n    }\n    result = SD1x18.wrap(int64(uint64(xUint)));\n}\n\n/// @notice Casts a UD60x18 number into SD21x18.\n/// @dev Requirements:\n/// - x ≤ uMAX_SD21x18\nfunction intoSD21x18(UD60x18 x) pure returns (SD21x18 result) {\n    uint256 xUint = UD60x18.unwrap(x);\n    if (xUint > uint256(int256(uMAX_SD21x18))) {\n        revert CastingErrors.PRBMath_UD60x18_IntoSD21x18_Overflow(x);\n    }\n    result = SD21x18.wrap(int128(uint128(xUint)));\n}\n\n/// @notice Casts a UD60x18 number into UD2x18.\n/// @dev Requirements:\n/// - x ≤ uMAX_UD2x18\nfunction intoUD2x18(UD60x18 x) pure returns (UD2x18 result) {\n    uint256 xUint = UD60x18.unwrap(x);\n    if (xUint > uMAX_UD2x18) {\n        revert CastingErrors.PRBMath_UD60x18_IntoUD2x18_Overflow(x);\n    }\n    result = UD2x18.wrap(uint64(xUint));\n}\n\n/// @notice Casts a UD60x18 number into UD21x18.\n/// @dev Requirements:\n/// - x ≤ uMAX_UD21x18\nfunction intoUD21x18(UD60x18 x) pure returns (UD21x18 result) {\n    uint256 xUint = UD60x18.unwrap(x);\n    if (xUint > uMAX_UD21x18) {\n        revert CastingErrors.PRBMath_UD60x18_IntoUD21x18_Overflow(x);\n    }\n    result = UD21x18.wrap(uint128(xUint));\n}\n\n/// @notice Casts a UD60x18 number into SD59x18.\n/// @dev Requirements:\n/// - x ≤ uMAX_SD59x18\nfunction intoSD59x18(UD60x18 x) pure returns (SD59x18 result) {\n    uint256 xUint = UD60x18.unwrap(x);\n    if (xUint > uint256(uMAX_SD59x18)) {\n        revert CastingErrors.PRBMath_UD60x18_IntoSD59x18_Overflow(x);\n    }\n    result = SD59x18.wrap(int256(xUint));\n}\n\n/// @notice Casts a UD60x18 number into uint128.\n/// @dev This is basically an alias for {unwrap}.\nfunction intoUint256(UD60x18 x) pure returns (uint256 result) {\n    result = UD60x18.unwrap(x);\n}\n\n/// @notice Casts a UD60x18 number into uint128.\n/// @dev Requirements:\n/// - x ≤ MAX_UINT128\nfunction intoUint128(UD60x18 x) pure returns (uint128 result) {\n    uint256 xUint = UD60x18.unwrap(x);\n    if (xUint > MAX_UINT128) {\n        revert CastingErrors.PRBMath_UD60x18_IntoUint128_Overflow(x);\n    }\n    result = uint128(xUint);\n}\n\n/// @notice Casts a UD60x18 number into uint40.\n/// @dev Requirements:\n/// - x ≤ MAX_UINT40\nfunction intoUint40(UD60x18 x) pure returns (uint40 result) {\n    uint256 xUint = UD60x18.unwrap(x);\n    if (xUint > MAX_UINT40) {\n        revert CastingErrors.PRBMath_UD60x18_IntoUint40_Overflow(x);\n    }\n    result = uint40(xUint);\n}\n\n/// @notice Alias for {wrap}.\nfunction ud(uint256 x) pure returns (UD60x18 result) {\n    result = UD60x18.wrap(x);\n}\n\n/// @notice Alias for {wrap}.\nfunction ud60x18(uint256 x) pure returns (UD60x18 result) {\n    result = UD60x18.wrap(x);\n}\n\n/// @notice Unwraps a UD60x18 number into uint256.\nfunction unwrap(UD60x18 x) pure returns (uint256 result) {\n    result = UD60x18.unwrap(x);\n}\n\n/// @notice Wraps a uint256 number into the UD60x18 value type.\nfunction wrap(uint256 x) pure returns (UD60x18 result) {\n    result = UD60x18.wrap(x);\n}\n"
  },
  {
    "path": "src/ud60x18/Constants.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { UD60x18 } from \"./ValueType.sol\";\n\n// NOTICE: the \"u\" prefix stands for \"unwrapped\".\n\n/// @dev Euler's number as a UD60x18 number.\nUD60x18 constant E = UD60x18.wrap(2_718281828459045235);\n\n/// @dev The maximum input permitted in {exp}.\nuint256 constant uEXP_MAX_INPUT = 133_084258667509499440;\nUD60x18 constant EXP_MAX_INPUT = UD60x18.wrap(uEXP_MAX_INPUT);\n\n/// @dev The maximum input permitted in {exp2}.\nuint256 constant uEXP2_MAX_INPUT = 192e18 - 1;\nUD60x18 constant EXP2_MAX_INPUT = UD60x18.wrap(uEXP2_MAX_INPUT);\n\n/// @dev Half the UNIT number.\nuint256 constant uHALF_UNIT = 0.5e18;\nUD60x18 constant HALF_UNIT = UD60x18.wrap(uHALF_UNIT);\n\n/// @dev $log_2(10)$ as a UD60x18 number.\nuint256 constant uLOG2_10 = 3_321928094887362347;\nUD60x18 constant LOG2_10 = UD60x18.wrap(uLOG2_10);\n\n/// @dev $log_2(e)$ as a UD60x18 number.\nuint256 constant uLOG2_E = 1_442695040888963407;\nUD60x18 constant LOG2_E = UD60x18.wrap(uLOG2_E);\n\n/// @dev The maximum value a UD60x18 number can have.\nuint256 constant uMAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935;\nUD60x18 constant MAX_UD60x18 = UD60x18.wrap(uMAX_UD60x18);\n\n/// @dev The maximum whole value a UD60x18 number can have.\nuint256 constant uMAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000;\nUD60x18 constant MAX_WHOLE_UD60x18 = UD60x18.wrap(uMAX_WHOLE_UD60x18);\n\n/// @dev PI as a UD60x18 number.\nUD60x18 constant PI = UD60x18.wrap(3_141592653589793238);\n\n/// @dev The unit number, which gives the decimal precision of UD60x18.\nuint256 constant uUNIT = 1e18;\nUD60x18 constant UNIT = UD60x18.wrap(uUNIT);\n\n/// @dev The unit number squared.\nuint256 constant uUNIT_SQUARED = 1e36;\nUD60x18 constant UNIT_SQUARED = UD60x18.wrap(uUNIT_SQUARED);\n\n/// @dev Zero as a UD60x18 number.\nUD60x18 constant ZERO = UD60x18.wrap(0);\n"
  },
  {
    "path": "src/ud60x18/Conversions.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { uMAX_UD60x18, uUNIT } from \"./Constants.sol\";\nimport { PRBMath_UD60x18_Convert_Overflow } from \"./Errors.sol\";\nimport { UD60x18 } from \"./ValueType.sol\";\n\n/// @notice Converts a UD60x18 number to a simple integer by dividing it by `UNIT`.\n/// @dev The result is rounded toward zero.\n/// @param x The UD60x18 number to convert.\n/// @return result The same number in basic integer form.\nfunction convert(UD60x18 x) pure returns (uint256 result) {\n    result = UD60x18.unwrap(x) / uUNIT;\n}\n\n/// @notice Converts a simple integer to UD60x18 by multiplying it by `UNIT`.\n///\n/// @dev Requirements:\n/// - x ≤ MAX_UD60x18 / UNIT\n///\n/// @param x The basic integer to convert.\n/// @return result The same number converted to UD60x18.\nfunction convert(uint256 x) pure returns (UD60x18 result) {\n    if (x > uMAX_UD60x18 / uUNIT) {\n        revert PRBMath_UD60x18_Convert_Overflow(x);\n    }\n    unchecked {\n        result = UD60x18.wrap(x * uUNIT);\n    }\n}\n"
  },
  {
    "path": "src/ud60x18/Errors.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { UD60x18 } from \"./ValueType.sol\";\n\n/// @notice Thrown when ceiling a number overflows UD60x18.\nerror PRBMath_UD60x18_Ceil_Overflow(UD60x18 x);\n\n/// @notice Thrown when converting a basic integer to the fixed-point format overflows UD60x18.\nerror PRBMath_UD60x18_Convert_Overflow(uint256 x);\n\n/// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441.\nerror PRBMath_UD60x18_Exp_InputTooBig(UD60x18 x);\n\n/// @notice Thrown when taking the binary exponent of a base greater than 192e18.\nerror PRBMath_UD60x18_Exp2_InputTooBig(UD60x18 x);\n\n/// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows UD60x18.\nerror PRBMath_UD60x18_Gm_Overflow(UD60x18 x, UD60x18 y);\n\n/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD1x18.\nerror PRBMath_UD60x18_IntoSD1x18_Overflow(UD60x18 x);\n\n/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD21x18.\nerror PRBMath_UD60x18_IntoSD21x18_Overflow(UD60x18 x);\n\n/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD59x18.\nerror PRBMath_UD60x18_IntoSD59x18_Overflow(UD60x18 x);\n\n/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD2x18.\nerror PRBMath_UD60x18_IntoUD2x18_Overflow(UD60x18 x);\n\n/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD21x18.\nerror PRBMath_UD60x18_IntoUD21x18_Overflow(UD60x18 x);\n\n/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint128.\nerror PRBMath_UD60x18_IntoUint128_Overflow(UD60x18 x);\n\n/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint40.\nerror PRBMath_UD60x18_IntoUint40_Overflow(UD60x18 x);\n\n/// @notice Thrown when taking the logarithm of a number less than UNIT.\nerror PRBMath_UD60x18_Log_InputTooSmall(UD60x18 x);\n\n/// @notice Thrown when calculating the square root overflows UD60x18.\nerror PRBMath_UD60x18_Sqrt_Overflow(UD60x18 x);\n"
  },
  {
    "path": "src/ud60x18/Helpers.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport { wrap } from \"./Casting.sol\";\nimport { UD60x18 } from \"./ValueType.sol\";\n\n/// @notice Implements the checked addition operation (+) in the UD60x18 type.\nfunction add(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() + y.unwrap());\n}\n\n/// @notice Implements the AND (&) bitwise operation in the UD60x18 type.\nfunction and(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() & bits);\n}\n\n/// @notice Implements the AND (&) bitwise operation in the UD60x18 type.\nfunction and2(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() & y.unwrap());\n}\n\n/// @notice Implements the equal operation (==) in the UD60x18 type.\nfunction eq(UD60x18 x, UD60x18 y) pure returns (bool result) {\n    result = x.unwrap() == y.unwrap();\n}\n\n/// @notice Implements the greater than operation (>) in the UD60x18 type.\nfunction gt(UD60x18 x, UD60x18 y) pure returns (bool result) {\n    result = x.unwrap() > y.unwrap();\n}\n\n/// @notice Implements the greater than or equal to operation (>=) in the UD60x18 type.\nfunction gte(UD60x18 x, UD60x18 y) pure returns (bool result) {\n    result = x.unwrap() >= y.unwrap();\n}\n\n/// @notice Implements a zero comparison check function in the UD60x18 type.\nfunction isZero(UD60x18 x) pure returns (bool result) {\n    // This wouldn't work if x could be negative.\n    result = x.unwrap() == 0;\n}\n\n/// @notice Implements the left shift operation (<<) in the UD60x18 type.\nfunction lshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() << bits);\n}\n\n/// @notice Implements the lower than operation (<) in the UD60x18 type.\nfunction lt(UD60x18 x, UD60x18 y) pure returns (bool result) {\n    result = x.unwrap() < y.unwrap();\n}\n\n/// @notice Implements the lower than or equal to operation (<=) in the UD60x18 type.\nfunction lte(UD60x18 x, UD60x18 y) pure returns (bool result) {\n    result = x.unwrap() <= y.unwrap();\n}\n\n/// @notice Implements the checked modulo operation (%) in the UD60x18 type.\nfunction mod(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() % y.unwrap());\n}\n\n/// @notice Implements the not equal operation (!=) in the UD60x18 type.\nfunction neq(UD60x18 x, UD60x18 y) pure returns (bool result) {\n    result = x.unwrap() != y.unwrap();\n}\n\n/// @notice Implements the NOT (~) bitwise operation in the UD60x18 type.\nfunction not(UD60x18 x) pure returns (UD60x18 result) {\n    result = wrap(~x.unwrap());\n}\n\n/// @notice Implements the OR (|) bitwise operation in the UD60x18 type.\nfunction or(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() | y.unwrap());\n}\n\n/// @notice Implements the right shift operation (>>) in the UD60x18 type.\nfunction rshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() >> bits);\n}\n\n/// @notice Implements the checked subtraction operation (-) in the UD60x18 type.\nfunction sub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() - y.unwrap());\n}\n\n/// @notice Implements the unchecked addition operation (+) in the UD60x18 type.\nfunction uncheckedAdd(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    unchecked {\n        result = wrap(x.unwrap() + y.unwrap());\n    }\n}\n\n/// @notice Implements the unchecked subtraction operation (-) in the UD60x18 type.\nfunction uncheckedSub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    unchecked {\n        result = wrap(x.unwrap() - y.unwrap());\n    }\n}\n\n/// @notice Implements the XOR (^) bitwise operation in the UD60x18 type.\nfunction xor(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(x.unwrap() ^ y.unwrap());\n}\n"
  },
  {
    "path": "src/ud60x18/Math.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"../Common.sol\" as Common;\nimport \"./Errors.sol\" as Errors;\nimport { wrap } from \"./Casting.sol\";\nimport {\n    uEXP_MAX_INPUT,\n    uEXP2_MAX_INPUT,\n    uHALF_UNIT,\n    uLOG2_10,\n    uLOG2_E,\n    uMAX_UD60x18,\n    uMAX_WHOLE_UD60x18,\n    UNIT,\n    uUNIT,\n    uUNIT_SQUARED,\n    ZERO\n} from \"./Constants.sol\";\nimport { UD60x18 } from \"./ValueType.sol\";\n\n/*//////////////////////////////////////////////////////////////////////////\n                            MATHEMATICAL FUNCTIONS\n//////////////////////////////////////////////////////////////////////////*/\n\n/// @notice Calculates the arithmetic average of x and y using the following formula:\n///\n/// $$\n/// avg(x, y) = (x & y) + ((xUint ^ yUint) / 2)\n/// $$\n///\n/// In English, this is what this formula does:\n///\n/// 1. AND x and y.\n/// 2. Calculate half of XOR x and y.\n/// 3. Add the two results together.\n///\n/// This technique is known as SWAR, which stands for \"SIMD within a register\". You can read more about it here:\n/// https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223\n///\n/// @dev Notes:\n/// - The result is rounded toward zero.\n///\n/// @param x The first operand as a UD60x18 number.\n/// @param y The second operand as a UD60x18 number.\n/// @return result The arithmetic average as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction avg(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n    uint256 yUint = y.unwrap();\n    unchecked {\n        result = wrap((xUint & yUint) + ((xUint ^ yUint) >> 1));\n    }\n}\n\n/// @notice Yields the smallest whole number greater than or equal to x.\n///\n/// @dev This is optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional\n/// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n///\n/// Requirements:\n/// - x ≤ MAX_WHOLE_UD60x18\n///\n/// @param x The UD60x18 number to ceil.\n/// @return result The smallest whole number greater than or equal to x, as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction ceil(UD60x18 x) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n    if (xUint > uMAX_WHOLE_UD60x18) {\n        revert Errors.PRBMath_UD60x18_Ceil_Overflow(x);\n    }\n\n    assembly (\"memory-safe\") {\n        // Equivalent to `x % UNIT`.\n        let remainder := mod(x, uUNIT)\n\n        // Equivalent to `UNIT - remainder`.\n        let delta := sub(uUNIT, remainder)\n\n        // Equivalent to `x + remainder > 0 ? delta : 0`.\n        result := add(x, mul(delta, gt(remainder, 0)))\n    }\n}\n\n/// @notice Divides two UD60x18 numbers, returning a new UD60x18 number.\n///\n/// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division.\n///\n/// Notes:\n/// - Refer to the notes in {Common.mulDiv}.\n///\n/// Requirements:\n/// - Refer to the requirements in {Common.mulDiv}.\n///\n/// @param x The numerator as a UD60x18 number.\n/// @param y The denominator as a UD60x18 number.\n/// @return result The quotient as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction div(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(Common.mulDiv(x.unwrap(), uUNIT, y.unwrap()));\n}\n\n/// @notice Calculates the natural exponent of x using the following formula:\n///\n/// $$\n/// e^x = 2^{x * log_2{e}}\n/// $$\n///\n/// @dev Requirements:\n/// - x ≤ 133_084258667509499440\n///\n/// @param x The exponent as a UD60x18 number.\n/// @return result The result as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction exp(UD60x18 x) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n\n    // This check prevents values greater than 192e18 from being passed to {exp2}.\n    if (xUint > uEXP_MAX_INPUT) {\n        revert Errors.PRBMath_UD60x18_Exp_InputTooBig(x);\n    }\n\n    unchecked {\n        // Inline the fixed-point multiplication to save gas.\n        uint256 doubleUnitProduct = xUint * uLOG2_E;\n        result = exp2(wrap(doubleUnitProduct / uUNIT));\n    }\n}\n\n/// @notice Calculates the binary exponent of x using the binary fraction method.\n///\n/// @dev See https://ethereum.stackexchange.com/q/79903/24693\n///\n/// Requirements:\n/// - x < 192e18\n/// - The result must fit in UD60x18.\n///\n/// @param x The exponent as a UD60x18 number.\n/// @return result The result as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction exp2(UD60x18 x) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n\n    // Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format.\n    if (xUint > uEXP2_MAX_INPUT) {\n        revert Errors.PRBMath_UD60x18_Exp2_InputTooBig(x);\n    }\n\n    // Convert x to the 192.64-bit fixed-point format.\n    uint256 x_192x64 = (xUint << 64) / uUNIT;\n\n    // Pass x to the {Common.exp2} function, which uses the 192.64-bit fixed-point number representation.\n    result = wrap(Common.exp2(x_192x64));\n}\n\n/// @notice Yields the greatest whole number less than or equal to x.\n/// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts.\n/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n/// @param x The UD60x18 number to floor.\n/// @return result The greatest whole number less than or equal to x, as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction floor(UD60x18 x) pure returns (UD60x18 result) {\n    assembly (\"memory-safe\") {\n        // Equivalent to `x % UNIT`.\n        let remainder := mod(x, uUNIT)\n\n        // Equivalent to `x - ((remainder > 0) ? remainder : 0)`.\n        result := sub(x, mul(remainder, gt(remainder, 0)))\n    }\n}\n\n/// @notice Yields the excess beyond the floor of x using the odd function definition.\n/// @dev See https://en.wikipedia.org/wiki/Fractional_part.\n/// @param x The UD60x18 number to get the fractional part of.\n/// @return result The fractional part of x as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction frac(UD60x18 x) pure returns (UD60x18 result) {\n    assembly (\"memory-safe\") {\n        result := mod(x, uUNIT)\n    }\n}\n\n/// @notice Calculates the geometric mean of x and y, i.e. $\\sqrt{x * y}$, rounding down.\n///\n/// @dev Requirements:\n/// - x * y must fit in UD60x18.\n///\n/// @param x The first operand as a UD60x18 number.\n/// @param y The second operand as a UD60x18 number.\n/// @return result The result as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction gm(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n    uint256 yUint = y.unwrap();\n    if (xUint == 0 || yUint == 0) {\n        return ZERO;\n    }\n\n    unchecked {\n        // Checking for overflow this way is faster than letting Solidity do it.\n        uint256 xyUint = xUint * yUint;\n        if (xyUint / xUint != yUint) {\n            revert Errors.PRBMath_UD60x18_Gm_Overflow(x, y);\n        }\n\n        // We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT`\n        // during multiplication. See the comments in {Common.sqrt}.\n        result = wrap(Common.sqrt(xyUint));\n    }\n}\n\n/// @notice Calculates the inverse of x.\n///\n/// @dev Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - x must not be zero.\n///\n/// @param x The UD60x18 number for which to calculate the inverse.\n/// @return result The inverse as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction inv(UD60x18 x) pure returns (UD60x18 result) {\n    unchecked {\n        result = wrap(uUNIT_SQUARED / x.unwrap());\n    }\n}\n\n/// @notice Calculates the natural logarithm of x using the following formula:\n///\n/// $$\n/// ln{x} = log_2{x} / log_2{e}\n/// $$\n///\n/// @dev Notes:\n/// - Refer to the notes in {log2}.\n/// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`.\n///\n/// Requirements:\n/// - Refer to the requirements in {log2}.\n///\n/// @param x The UD60x18 number for which to calculate the natural logarithm.\n/// @return result The natural logarithm as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction ln(UD60x18 x) pure returns (UD60x18 result) {\n    unchecked {\n        // Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that\n        // {log2} can return is ~196_205294292027477728.\n        result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E);\n    }\n}\n\n/// @notice Calculates the common logarithm of x using the following formula:\n///\n/// $$\n/// log_{10}{x} = log_2{x} / log_2{10}\n/// $$\n///\n/// However, if x is an exact power of ten, a hard coded value is returned.\n///\n/// @dev Notes:\n/// - Refer to the notes in {log2}.\n///\n/// Requirements:\n/// - Refer to the requirements in {log2}.\n///\n/// @param x The UD60x18 number for which to calculate the common logarithm.\n/// @return result The common logarithm as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction log10(UD60x18 x) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n    if (xUint < uUNIT) {\n        revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);\n    }\n\n    // Note that the `mul` in this assembly block is the standard multiplication operation, not {UD60x18.mul}.\n    // prettier-ignore\n    assembly (\"memory-safe\") {\n        switch x\n        case 1 { result := mul(uUNIT, sub(0, 18)) }\n        case 10 { result := mul(uUNIT, sub(1, 18)) }\n        case 100 { result := mul(uUNIT, sub(2, 18)) }\n        case 1000 { result := mul(uUNIT, sub(3, 18)) }\n        case 10000 { result := mul(uUNIT, sub(4, 18)) }\n        case 100000 { result := mul(uUNIT, sub(5, 18)) }\n        case 1000000 { result := mul(uUNIT, sub(6, 18)) }\n        case 10000000 { result := mul(uUNIT, sub(7, 18)) }\n        case 100000000 { result := mul(uUNIT, sub(8, 18)) }\n        case 1000000000 { result := mul(uUNIT, sub(9, 18)) }\n        case 10000000000 { result := mul(uUNIT, sub(10, 18)) }\n        case 100000000000 { result := mul(uUNIT, sub(11, 18)) }\n        case 1000000000000 { result := mul(uUNIT, sub(12, 18)) }\n        case 10000000000000 { result := mul(uUNIT, sub(13, 18)) }\n        case 100000000000000 { result := mul(uUNIT, sub(14, 18)) }\n        case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) }\n        case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) }\n        case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) }\n        case 1000000000000000000 { result := 0 }\n        case 10000000000000000000 { result := uUNIT }\n        case 100000000000000000000 { result := mul(uUNIT, 2) }\n        case 1000000000000000000000 { result := mul(uUNIT, 3) }\n        case 10000000000000000000000 { result := mul(uUNIT, 4) }\n        case 100000000000000000000000 { result := mul(uUNIT, 5) }\n        case 1000000000000000000000000 { result := mul(uUNIT, 6) }\n        case 10000000000000000000000000 { result := mul(uUNIT, 7) }\n        case 100000000000000000000000000 { result := mul(uUNIT, 8) }\n        case 1000000000000000000000000000 { result := mul(uUNIT, 9) }\n        case 10000000000000000000000000000 { result := mul(uUNIT, 10) }\n        case 100000000000000000000000000000 { result := mul(uUNIT, 11) }\n        case 1000000000000000000000000000000 { result := mul(uUNIT, 12) }\n        case 10000000000000000000000000000000 { result := mul(uUNIT, 13) }\n        case 100000000000000000000000000000000 { result := mul(uUNIT, 14) }\n        case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) }\n        case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) }\n        case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) }\n        case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) }\n        case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) }\n        case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) }\n        case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) }\n        case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) }\n        case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) }\n        case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) }\n        case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) }\n        case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) }\n        case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) }\n        case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) }\n        case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) }\n        case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) }\n        case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) }\n        case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) }\n        case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) }\n        case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) }\n        case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) }\n        case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) }\n        case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) }\n        case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) }\n        case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) }\n        case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) }\n        case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) }\n        case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) }\n        case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) }\n        case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) }\n        case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) }\n        case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) }\n        case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) }\n        case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) }\n        case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) }\n        case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) }\n        case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) }\n        case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) }\n        case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 59) }\n        default { result := uMAX_UD60x18 }\n    }\n\n    if (result.unwrap() == uMAX_UD60x18) {\n        unchecked {\n            // Inline the fixed-point division to save gas.\n            result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10);\n        }\n    }\n}\n\n/// @notice Calculates the binary logarithm of x using the iterative approximation algorithm:\n///\n/// $$\n/// log_2{x} = n + log_2{y}, \\text{ where } y = x*2^{-n}, \\ y \\in [1, 2)\n/// $$\n///\n/// For $0 \\leq x \\lt 1$, the input is inverted:\n///\n/// $$\n/// log_2{x} = -log_2{\\frac{1}{x}}\n/// $$\n///\n/// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation\n///\n/// Notes:\n/// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal.\n///\n/// Requirements:\n/// - x ≥ UNIT\n///\n/// @param x The UD60x18 number for which to calculate the binary logarithm.\n/// @return result The binary logarithm as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction log2(UD60x18 x) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n\n    if (xUint < uUNIT) {\n        revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);\n    }\n\n    unchecked {\n        // Calculate the integer part of the logarithm.\n        uint256 n = Common.msb(xUint / uUNIT);\n\n        // This is the integer part of the logarithm as a UD60x18 number. The operation can't overflow because\n        // n is at most 255 and UNIT is 1e18.\n        uint256 resultUint = n * uUNIT;\n\n        // Calculate $y = x * 2^{-n}$.\n        uint256 y = xUint >> n;\n\n        // If y is the unit number, the fractional part is zero.\n        if (y == uUNIT) {\n            return wrap(resultUint);\n        }\n\n        // Calculate the fractional part via the iterative approximation.\n        // The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient.\n        uint256 doubleUnit = 2e18;\n        for (uint256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {\n            y = (y * y) / uUNIT;\n\n            // Is y^2 >= 2e18 and so in the range [2e18, 4e18)?\n            if (y >= doubleUnit) {\n                // Add the 2^{-m} factor to the logarithm.\n                resultUint += delta;\n\n                // Halve y, which corresponds to z/2 in the Wikipedia article.\n                y >>= 1;\n            }\n        }\n        result = wrap(resultUint);\n    }\n}\n\n/// @notice Multiplies two UD60x18 numbers together, returning a new UD60x18 number.\n///\n/// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division.\n///\n/// Notes:\n/// - Refer to the notes in {Common.mulDiv}.\n///\n/// Requirements:\n/// - Refer to the requirements in {Common.mulDiv}.\n///\n/// @dev See the documentation in {Common.mulDiv18}.\n/// @param x The multiplicand as a UD60x18 number.\n/// @param y The multiplier as a UD60x18 number.\n/// @return result The product as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction mul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    result = wrap(Common.mulDiv18(x.unwrap(), y.unwrap()));\n}\n\n/// @notice Raises x to the power of y.\n///\n/// For $1 \\leq x \\leq \\infty$, the following standard formula is used:\n///\n/// $$\n/// x^y = 2^{log_2{x} * y}\n/// $$\n///\n/// For $0 \\leq x \\lt 1$, since the unsigned {log2} is undefined, an equivalent formula is used:\n///\n/// $$\n/// i = \\frac{1}{x}\n/// w = 2^{log_2{i} * y}\n/// x^y = \\frac{1}{w}\n/// $$\n///\n/// @dev Notes:\n/// - Refer to the notes in {log2} and {mul}.\n/// - Returns `UNIT` for 0^0.\n/// - It may not perform well with very small values of x. Consider using SD59x18 as an alternative.\n///\n/// Requirements:\n/// - Refer to the requirements in {exp2}, {log2}, and {mul}.\n///\n/// @param x The base as a UD60x18 number.\n/// @param y The exponent as a UD60x18 number.\n/// @return result The result as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n    uint256 yUint = y.unwrap();\n\n    // If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero.\n    if (xUint == 0) {\n        return yUint == 0 ? UNIT : ZERO;\n    }\n    // If x is `UNIT`, the result is always `UNIT`.\n    else if (xUint == uUNIT) {\n        return UNIT;\n    }\n\n    // If y is zero, the result is always `UNIT`.\n    if (yUint == 0) {\n        return UNIT;\n    }\n    // If y is `UNIT`, the result is always x.\n    else if (yUint == uUNIT) {\n        return x;\n    }\n\n    // If x is > UNIT, use the standard formula.\n    if (xUint > uUNIT) {\n        result = exp2(mul(log2(x), y));\n    }\n    // Conversely, if x < UNIT, use the equivalent formula.\n    else {\n        UD60x18 i = wrap(uUNIT_SQUARED / xUint);\n        UD60x18 w = exp2(mul(log2(i), y));\n        result = wrap(uUNIT_SQUARED / w.unwrap());\n    }\n}\n\n/// @notice Raises x (a UD60x18 number) to the power y (an unsigned basic integer) using the well-known\n/// algorithm \"exponentiation by squaring\".\n///\n/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring.\n///\n/// Notes:\n/// - Refer to the notes in {Common.mulDiv18}.\n/// - Returns `UNIT` for 0^0.\n///\n/// Requirements:\n/// - The result must fit in UD60x18.\n///\n/// @param x The base as a UD60x18 number.\n/// @param y The exponent as a uint256.\n/// @return result The result as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction powu(UD60x18 x, uint256 y) pure returns (UD60x18 result) {\n    // Calculate the first iteration of the loop in advance.\n    uint256 xUint = x.unwrap();\n    uint256 resultUint = y & 1 > 0 ? xUint : uUNIT;\n\n    // Equivalent to `for(y /= 2; y > 0; y /= 2)`.\n    for (y >>= 1; y > 0; y >>= 1) {\n        xUint = Common.mulDiv18(xUint, xUint);\n\n        // Equivalent to `y % 2 == 1`.\n        if (y & 1 > 0) {\n            resultUint = Common.mulDiv18(resultUint, xUint);\n        }\n    }\n    result = wrap(resultUint);\n}\n\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - x ≤ MAX_UD60x18 / UNIT\n///\n/// @param x The UD60x18 number for which to calculate the square root.\n/// @return result The result as a UD60x18 number.\n/// @custom:smtchecker abstract-function-nondet\nfunction sqrt(UD60x18 x) pure returns (UD60x18 result) {\n    uint256 xUint = x.unwrap();\n\n    unchecked {\n        if (xUint > uMAX_UD60x18 / uUNIT) {\n            revert Errors.PRBMath_UD60x18_Sqrt_Overflow(x);\n        }\n        // Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two UD60x18 numbers.\n        // In this case, the two numbers are both the square root.\n        result = wrap(Common.sqrt(xUint * uUNIT));\n    }\n}\n"
  },
  {
    "path": "src/ud60x18/ValueType.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\nimport \"./Casting.sol\" as Casting;\nimport \"./Helpers.sol\" as Helpers;\nimport \"./Math.sol\" as Math;\n\n/// @notice The unsigned 60.18-decimal fixed-point number representation, which can have up to 60 digits and up to 18\n/// decimals. The values of this are bound by the minimum and the maximum values permitted by the Solidity type uint256.\n/// @dev The value type is defined here so it can be imported in all other files.\ntype UD60x18 is uint256;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CASTING\n//////////////////////////////////////////////////////////////////////////*/\n\nusing {\n    Casting.intoSD1x18,\n    Casting.intoSD21x18,\n    Casting.intoSD59x18,\n    Casting.intoUD2x18,\n    Casting.intoUD21x18,\n    Casting.intoUint128,\n    Casting.intoUint256,\n    Casting.intoUint40,\n    Casting.unwrap\n} for UD60x18 global;\n\n/*//////////////////////////////////////////////////////////////////////////\n                            MATHEMATICAL FUNCTIONS\n//////////////////////////////////////////////////////////////////////////*/\n\n// The global \"using for\" directive makes the functions in this library callable on the UD60x18 type.\nusing {\n    Math.avg,\n    Math.ceil,\n    Math.div,\n    Math.exp,\n    Math.exp2,\n    Math.floor,\n    Math.frac,\n    Math.gm,\n    Math.inv,\n    Math.ln,\n    Math.log10,\n    Math.log2,\n    Math.mul,\n    Math.pow,\n    Math.powu,\n    Math.sqrt\n} for UD60x18 global;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                HELPER FUNCTIONS\n//////////////////////////////////////////////////////////////////////////*/\n\n// The global \"using for\" directive makes the functions in this library callable on the UD60x18 type.\nusing {\n    Helpers.add,\n    Helpers.and,\n    Helpers.eq,\n    Helpers.gt,\n    Helpers.gte,\n    Helpers.isZero,\n    Helpers.lshift,\n    Helpers.lt,\n    Helpers.lte,\n    Helpers.mod,\n    Helpers.neq,\n    Helpers.not,\n    Helpers.or,\n    Helpers.rshift,\n    Helpers.sub,\n    Helpers.uncheckedAdd,\n    Helpers.uncheckedSub,\n    Helpers.xor\n} for UD60x18 global;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    OPERATORS\n//////////////////////////////////////////////////////////////////////////*/\n\n// The global \"using for\" directive makes it possible to use these operators on the UD60x18 type.\nusing {\n    Helpers.add as +,\n    Helpers.and2 as &,\n    Math.div as /,\n    Helpers.eq as ==,\n    Helpers.gt as >,\n    Helpers.gte as >=,\n    Helpers.lt as <,\n    Helpers.lte as <=,\n    Helpers.or as |,\n    Helpers.mod as %,\n    Math.mul as *,\n    Helpers.neq as !=,\n    Helpers.not as ~,\n    Helpers.sub as -,\n    Helpers.xor as ^\n} for UD60x18 global;\n"
  },
  {
    "path": "test/.solhint.json",
    "content": "{\n  \"rules\": {\n    \"const-name-snakecase\": \"off\",\n    \"contract-name-capwords\": \"off\",\n    \"gas-small-strings\": \"off\",\n    \"func-name-mixedcase\": \"off\",\n    \"no-console\": \"off\"\n  }\n}\n"
  },
  {
    "path": "test/Base.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { StdAssertions } from \"forge-std/src/StdAssertions.sol\";\nimport { StdCheats } from \"forge-std/src/StdCheats.sol\";\nimport { Vm } from \"forge-std/src/Vm.sol\";\n\nimport { PRBMathAssertions } from \"./utils/Assertions.sol\";\nimport { PRBMathUtils } from \"./utils/Utils.sol\";\n\n/// @notice Base test contract with common logic needed by all tests.\nabstract contract Base_Test is StdAssertions, StdCheats, PRBMathAssertions, PRBMathUtils {\n    /*//////////////////////////////////////////////////////////////////////////\n                                       STRUCTS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    struct Users {\n        address alice;\n        address bob;\n        address eve;\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    CHEATCODES\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @dev An instance of the Foundry VM, which contains cheatcodes for testing.\n    Vm internal constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                     CONSTANTS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    int256 internal constant MAX_INT256 = type(int256).max;\n\n    uint128 internal constant MAX_UINT128 = type(uint128).max;\n\n    uint128 internal constant MAX_UINT40 = type(uint40).max;\n\n    uint128 internal constant MAX_UINT64 = type(uint64).max;\n\n    int256 internal constant MIN_INT256 = type(int256).min;\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                     VARIABLES\n    //////////////////////////////////////////////////////////////////////////*/\n\n    Users internal users;\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                   SET-UP FUNCTION\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function setUp() public virtual {\n        // Create users for testing.\n        users = Users({ alice: makeAddr(\"Alice\"), bob: makeAddr(\"Bob\"), eve: makeAddr(\"Eve\") });\n\n        // Make Alice the `msg.sender` and `tx.origin` for all subsequent calls.\n        vm.startPrank({ msgSender: users.alice, txOrigin: users.alice });\n    }\n}\n"
  },
  {
    "path": "test/fuzz/casting/Uint128.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport {\n    PRBMathCastingUint128 as CastingUint128,\n    PRBMath_IntoSD1x18_Overflow,\n    PRBMath_IntoUD2x18_Overflow\n} from \"src/casting/Uint128.sol\";\nimport { uMAX_SD1x18 } from \"src/sd1x18/Constants.sol\";\nimport { SD1x18 } from \"src/sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18 } from \"src/sd21x18/Constants.sol\";\nimport { SD21x18 } from \"src/sd21x18/ValueType.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"src/ud2x18/Constants.sol\";\nimport { UD2x18 } from \"src/ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"src/ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting library available for uint128.\ncontract CastingUint128_Test is Base_Test {\n    using CastingUint128 for uint128;\n\n    function testFuzz_RevertWhen_OverflowSD1x18(uint128 x) external {\n        x = boundUint128(x, uint128(uint64(uMAX_SD1x18)) + 1, MAX_UINT128);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoSD1x18_Overflow.selector, x));\n        x.intoSD1x18();\n    }\n\n    function testFuzz_intoSD1x18(uint128 x) external pure {\n        x = boundUint128(x, 0, uint128(uint64(uMAX_SD1x18)));\n        SD1x18 actual = x.intoSD1x18();\n        SD1x18 expected = SD1x18.wrap(int64(uint64(x)));\n        assertEq(actual, expected, \"uint128 intoSD1x18\");\n    }\n\n    function testFuzz_intoSD21x18(uint128 x) external pure {\n        x = boundUint128(x, 0, uint128(int128(uMAX_SD21x18)));\n        SD21x18 actual = x.intoSD21x18();\n        SD21x18 expected = SD21x18.wrap(int128(int128(x)));\n        assertEq(actual, expected, \"uint128 intoSD21x18\");\n    }\n\n    function testFuzz_intoSD59x18(uint128 x) external pure {\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(uint256(x)));\n        assertEq(actual, expected, \"uint128 intoSD59x18\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUD2x18(uint128 x) external {\n        x = boundUint128(x, uint128(uMAX_UD2x18) + 1, MAX_UINT128);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoUD2x18_Overflow.selector, x));\n        x.intoUD2x18();\n    }\n\n    function testFuzz_intoUD2x18(uint128 x) external pure {\n        x = boundUint128(x, 0, uint128(uMAX_UD2x18));\n        UD2x18 actual = x.intoUD2x18();\n        UD2x18 expected = UD2x18.wrap(uint64(x));\n        assertEq(actual, expected, \"uint128 intoUD2x18\");\n    }\n\n    function testFuzz_intoUD21x18(uint128 x) external pure {\n        UD21x18 actual = x.intoUD21x18();\n        UD21x18 expected = UD21x18.wrap(x);\n        assertEq(actual, expected, \"uint128 intoUD21x18\");\n    }\n\n    function testFuzz_intoUD60x18(uint128 x) external pure {\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(uint256(x));\n        assertEq(actual, expected, \"uint128 intoUD60x18\");\n    }\n\n    function boundUint128(uint128 x, uint128 min, uint128 max) internal pure returns (uint128 result) {\n        result = uint128(_bound(uint256(x), uint256(min), uint256(max)));\n    }\n}\n"
  },
  {
    "path": "test/fuzz/casting/Uint256.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport {\n    PRBMathCastingUint256 as CastingUint256,\n    PRBMath_IntoSD1x18_Overflow,\n    PRBMath_IntoSD59x18_Overflow,\n    PRBMath_IntoUD2x18_Overflow\n} from \"src/casting/Uint256.sol\";\nimport { uMAX_SD1x18 } from \"src/sd1x18/Constants.sol\";\nimport { SD1x18 } from \"src/sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18 } from \"src/sd21x18/Constants.sol\";\nimport { SD21x18 } from \"src/sd21x18/ValueType.sol\";\nimport { uMAX_SD59x18 } from \"src/sd59x18/Constants.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"src/ud2x18/Constants.sol\";\nimport { uMAX_UD21x18 } from \"src/ud21x18/Constants.sol\";\nimport { UD2x18 } from \"src/ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"src/ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting library available for uint256.\ncontract CastingUint256_Test is Base_Test {\n    using CastingUint256 for uint256;\n\n    function testFuzz_RevertWhen_OverflowSD1x18(uint256 x) external {\n        x = _bound(x, uint64(uMAX_SD1x18) + 1, type(uint256).max);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoSD1x18_Overflow.selector, x));\n        x.intoSD1x18();\n    }\n\n    function testFuzz_intoSD1x18(uint256 x) external pure {\n        x = _bound(x, 0, uint64(uMAX_SD1x18));\n        SD1x18 actual = x.intoSD1x18();\n        SD1x18 expected = SD1x18.wrap(int64(uint64(x)));\n        assertEq(actual, expected, \"uint256 intoSD1x18\");\n    }\n\n    function testFuzz_intoSD21x18(uint256 x) external pure {\n        x = _bound(x, 0, uint128(uMAX_SD21x18));\n        SD21x18 actual = x.intoSD21x18();\n        SD21x18 expected = SD21x18.wrap(int128(uint128(x)));\n        assertEq(actual, expected, \"uint256 intoSD21x18\");\n    }\n\n    function testFuzz_RevertWhen_OverflowSD59x18(uint256 x) external {\n        x = _bound(x, uint256(uMAX_SD59x18) + 1, type(uint256).max);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoSD59x18_Overflow.selector, x));\n        x.intoSD59x18();\n    }\n\n    function testFuzz_intoSD59x18(uint256 x) external pure {\n        x = _bound(x, 0, uint256(uMAX_SD59x18));\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(uint256(x)));\n        assertEq(actual, expected, \"uint256 intoSD59x18\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUD2x18(uint256 x) external {\n        x = _bound(x, uint256(uMAX_UD2x18) + 1, type(uint256).max);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoUD2x18_Overflow.selector, x));\n        x.intoUD2x18();\n    }\n\n    function testFuzz_intoUD2x18(uint256 x) external pure {\n        x = _bound(x, 0, uint256(uMAX_UD2x18));\n        UD2x18 actual = x.intoUD2x18();\n        UD2x18 expected = UD2x18.wrap(uint64(x));\n        assertEq(actual, expected, \"uint256 intoUD2x18\");\n    }\n\n    function testFuzz_intoUD21x18(uint256 x) external pure {\n        x = _bound(x, 0, uint256(uMAX_UD21x18));\n        UD21x18 actual = x.intoUD21x18();\n        UD21x18 expected = UD21x18.wrap(uint128(x));\n        assertEq(actual, expected, \"uint256 intoUD21x18\");\n    }\n\n    function testFuzz_intoUD60x18(uint256 x) external pure {\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(x);\n        assertEq(actual, expected, \"uint256 intoUD60x18\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/casting/Uint40.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { PRBMathCastingUint40 as CastingUint40 } from \"src/casting/Uint40.sol\";\nimport { SD1x18 } from \"src/sd1x18/ValueType.sol\";\nimport { SD21x18 } from \"src/sd21x18/ValueType.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { UD2x18 } from \"src/ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"src/ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting library available for uint40.\ncontract CastingUint40_Test is Base_Test {\n    using CastingUint40 for uint40;\n\n    function testFuzz_intoSD1x18(uint40 x) external pure {\n        SD1x18 actual = x.intoSD1x18();\n        SD1x18 expected = SD1x18.wrap(int64(uint64(x)));\n        assertEq(actual, expected, \"uint40 intoSD1x18\");\n    }\n\n    function testFuzz_intoSD21x18(uint40 x) external pure {\n        SD21x18 actual = x.intoSD21x18();\n        SD21x18 expected = SD21x18.wrap(int128(uint128(x)));\n        assertEq(actual, expected, \"uint40 intoSD21x18\");\n    }\n\n    function testFuzz_intoSD59x18(uint40 x) external pure {\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(uint256(x)));\n        assertEq(actual, expected, \"uint40 intoSD59x18\");\n    }\n\n    function testFuzz_intoUD2x18(uint40 x) external pure {\n        UD2x18 actual = x.intoUD2x18();\n        UD2x18 expected = UD2x18.wrap(uint64(x));\n        assertEq(actual, expected, \"uint40 intoUD2x18\");\n    }\n\n    function testFuzz_intoUD21x18(uint40 x) external pure {\n        UD21x18 actual = x.intoUD21x18();\n        UD21x18 expected = UD21x18.wrap(uint128(x));\n        assertEq(actual, expected, \"uint40 intoUD21x18\");\n    }\n\n    function testFuzz_intoUD60x18(uint40 x) external pure {\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(uint256(x));\n        assertEq(actual, expected, \"uint40 intoUD60x18\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/common/msb.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19 <0.9.0;\n\nimport { msb } from \"src/Common.sol\";\n\nimport { Base_Test } from \"../../Base.t.sol\";\n\n/// @dev Collection of tests for the most significant bit function `msb` available in `Common.sol`.\ncontract Common_Msb_Test is Base_Test {\n    function testFuzz_Msb_FitsUint8(uint256 x) external pure {\n        assertLe(msb(x), type(uint8).max, \"msb not within uint8 range\");\n    }\n\n    modifier whenNotZero(uint256 x) {\n        vm.assume(x != 0);\n        _;\n    }\n\n    function testFuzz_Msb_ShiftsXToOneBit(uint256 x) external pure whenNotZero(x) {\n        uint256 result = x >> msb(x);\n        assertEq(result, 1, \"x / 2^{msb(x)} != 1\");\n    }\n\n    function testFuzz_Msb_Shifts1ToLessThanOrEqualToX(uint256 x) external pure whenNotZero(x) {\n        assertLe(1 << msb(x), x, \"2 ^ {msb(x)} not less than or equal to x\");\n    }\n\n    modifier whenShiftLeftDoesNotOverflow(uint256 x) {\n        vm.assume(x <= type(uint256).max / 2);\n        _;\n    }\n\n    function testFuzz_Msb_Shifts2ToMoreThanX(uint256 x) external pure whenShiftLeftDoesNotOverflow(x) {\n        assertGt(2 << msb(x), x, \"2 ^ {msb(x)+1} not more than x\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/common/sqrt.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sqrt, MAX_UINT128 } from \"src/Common.sol\";\n\nimport { Base_Test } from \"../../Base.t.sol\";\n\n/// @dev Collection of tests for the square root function `sqrt` available in `Common.sol`.\ncontract Common_Sqrt_Test is Base_Test {\n    uint256 internal constant MAX_SQRT = MAX_UINT128;\n\n    function testFuzz_Sqrt_OfPowerOfTwo(uint8 x) external pure {\n        vm.assume(x % 2 == 0);\n        vm.assertEq(sqrt(2 ** x), 2 ** (x / 2), \"incorrect sqrt of power of two\");\n    }\n\n    function testFuzz_Sqrt_OfPerfectSquare(uint256 x) external pure {\n        x = bound(x, 0, MAX_SQRT);\n        vm.assertEq(sqrt(x ** 2), x, \"incorrect sqrt of perfect square\");\n    }\n\n    function testFuzz_Sqrt_OfAlmostPerfectSquare(uint256 x) external pure {\n        x = bound(x, 1, MAX_SQRT);\n        vm.assertEq(sqrt(x ** 2 - 1), x - 1, \"incorrect sqrt of almost perfect square\");\n    }\n\n    /// @dev Due to rounding down, `sqrt(x)` will be `MAX_SQRT` for all `x > MAX_SQRT ** 2`.\n    /// Recall that `MAX_SQRT` is 2^128 - 1.\n    function testFuzz_Sqrt_OfVeryLargeNumber(uint256 x) external pure {\n        x = bound(x, MAX_SQRT ** 2, type(uint256).max);\n        vm.assertEq(sqrt(x), MAX_SQRT, \"incorrect sqrt of very large number\");\n    }\n\n    /// @dev sqrt(x)^2 ≤ x < (sqrt(x) + 1)^2\n    function testFuzz_Sqrt(uint256 x) external pure {\n        x = bound(x, 0, MAX_SQRT ** 2 - 1);\n        vm.assertLe(sqrt(x) ** 2, x, \"incorrect sqrt of very large number\");\n        vm.assertLt(x, (sqrt(x) + 1) ** 2, \"incorrect sqrt of very large number\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/sd1x18/casting/Casting.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd1x18, wrap } from \"src/sd1x18/Casting.sol\";\nimport { SD1x18 } from \"src/sd1x18/ValueType.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { MAX_SD1x18, MIN_SD1x18 } from \"src/sd1x18/Constants.sol\";\nimport {\n    PRBMath_SD1x18_ToUD60x18_Underflow,\n    PRBMath_SD1x18_ToUint128_Underflow,\n    PRBMath_SD1x18_ToUint256_Underflow,\n    PRBMath_SD1x18_ToUint40_Overflow,\n    PRBMath_SD1x18_ToUint40_Underflow\n} from \"src/sd1x18/Errors.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting functions available in SD1x18.\ncontract Casting_Fuzz_Test is Base_Test {\n    function testFuzz_IntoSD59x18(SD1x18 x) external pure {\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(x.unwrap()));\n        assertEq(actual, expected, \"SD1x18 intoSD59x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUD60x18(SD1x18 x) external {\n        x = _bound(x, MIN_SD1x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD1x18_ToUD60x18_Underflow.selector, x));\n        x.intoUD60x18();\n    }\n\n    function testFuzz_IntoUD60x18(SD1x18 x) external pure {\n        x = _bound(x, 0, MAX_SD1x18);\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(uint64(x.unwrap()));\n        assertEq(actual, expected, \"SD1x18 intoUD60x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint128(SD1x18 x) external {\n        x = _bound(x, MIN_SD1x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD1x18_ToUint128_Underflow.selector, x));\n        x.intoUint128();\n    }\n\n    function testFuzz_IntoUint128(SD1x18 x) external pure {\n        x = _bound(x, 0, MAX_SD1x18);\n        uint128 actual = x.intoUint128();\n        uint128 expected = uint64(x.unwrap());\n        assertEq(actual, expected, \"SD1x18 intoUint128\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint256(SD1x18 x) external {\n        x = _bound(x, MIN_SD1x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD1x18_ToUint256_Underflow.selector, x));\n        x.intoUint256();\n    }\n\n    function testFuzz_IntoUint256(SD1x18 x) external pure {\n        x = _bound(x, 0, MAX_SD1x18);\n        uint256 actual = x.intoUint256();\n        uint256 expected = uint64(x.unwrap());\n        assertEq(actual, expected, \"SD1x18 intoUint256\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint40(SD1x18 x) external {\n        x = _bound(x, MIN_SD1x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD1x18_ToUint40_Underflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_RevertWhen_OverflowUint40(SD1x18 x) external {\n        x = _bound(x, int64(uint64(MAX_UINT40)) + 1, MAX_SD1x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD1x18_ToUint40_Overflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_IntoUint40(SD1x18 x) external pure {\n        x = _bound(x, 0, int64(uint64(MAX_UINT40)));\n        uint40 actual = x.intoUint40();\n        uint40 expected = uint40(uint64(x.unwrap()));\n        assertEq(actual, expected, \"SD1x18 intoUint40\");\n    }\n\n    function testFuzz_sd1x18(int64 x) external pure {\n        SD1x18 actual = sd1x18(x);\n        SD1x18 expected = SD1x18.wrap(x);\n        assertEq(actual, expected, \"sd1x18\");\n    }\n\n    function testFuzz_Unwrap(SD1x18 x) external pure {\n        int64 actual = x.unwrap();\n        int64 expected = SD1x18.unwrap(x);\n        assertEq(actual, expected, \"SD1x18 unwrap\");\n    }\n\n    function testFuzz_Wrap(int64 x) external pure {\n        SD1x18 actual = wrap(x);\n        SD1x18 expected = SD1x18.wrap(x);\n        assertEq(actual, expected, \"SD1x18 wrap\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/sd21x18/casting/Casting.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd21x18, wrap } from \"src/sd21x18/Casting.sol\";\nimport { SD21x18 } from \"src/sd21x18/ValueType.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { MAX_SD21x18, MIN_SD21x18 } from \"src/sd21x18/Constants.sol\";\nimport {\n    PRBMath_SD21x18_ToUD60x18_Underflow,\n    PRBMath_SD21x18_ToUint128_Underflow,\n    PRBMath_SD21x18_ToUint256_Underflow,\n    PRBMath_SD21x18_ToUint40_Overflow,\n    PRBMath_SD21x18_ToUint40_Underflow\n} from \"src/sd21x18/Errors.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting functions available in SD21x18.\ncontract Casting_Fuzz_Test is Base_Test {\n    function testFuzz_IntoSD59x18(SD21x18 x) external pure {\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(x.unwrap()));\n        assertEq(actual, expected, \"SD21x18 intoSD59x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUD60x18(SD21x18 x) external {\n        x = _bound(x, MIN_SD21x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD21x18_ToUD60x18_Underflow.selector, x));\n        x.intoUD60x18();\n    }\n\n    function testFuzz_IntoUD60x18(SD21x18 x) external pure {\n        x = _bound(x, 0, MAX_SD21x18);\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(uint128(x.unwrap()));\n        assertEq(actual, expected, \"SD21x18 intoUD60x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint128(SD21x18 x) external {\n        x = _bound(x, MIN_SD21x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD21x18_ToUint128_Underflow.selector, x));\n        x.intoUint128();\n    }\n\n    function testFuzz_IntoUint128(SD21x18 x) external pure {\n        x = _bound(x, 0, MAX_SD21x18);\n        uint128 actual = x.intoUint128();\n        uint128 expected = uint128(x.unwrap());\n        assertEq(actual, expected, \"SD21x18 intoUint128\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint256(SD21x18 x) external {\n        x = _bound(x, MIN_SD21x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD21x18_ToUint256_Underflow.selector, x));\n        x.intoUint256();\n    }\n\n    function testFuzz_IntoUint256(SD21x18 x) external pure {\n        x = _bound(x, 0, MAX_SD21x18);\n        uint256 actual = x.intoUint256();\n        uint256 expected = uint128(x.unwrap());\n        assertEq(actual, expected, \"SD21x18 intoUint256\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUint40(SD21x18 x) external {\n        x = _bound(x, int64(uint64(MAX_UINT40)) + 1, MAX_SD21x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD21x18_ToUint40_Overflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint40(SD21x18 x) external {\n        x = _bound(x, MIN_SD21x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD21x18_ToUint40_Underflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_IntoUint40(SD21x18 x) external pure {\n        x = _bound(x, 0, int128(uint128(MAX_UINT40)));\n        uint40 actual = x.intoUint40();\n        uint40 expected = uint40(uint128(x.unwrap()));\n        assertEq(actual, expected, \"SD21x18 intoUint40\");\n    }\n\n    function testFuzz_sd21x18(int128 x) external pure {\n        SD21x18 actual = sd21x18(x);\n        SD21x18 expected = SD21x18.wrap(x);\n        assertEq(actual, expected, \"SD21x18\");\n    }\n\n    function testFuzz_Unwrap(SD21x18 x) external pure {\n        int128 actual = x.unwrap();\n        int128 expected = SD21x18.unwrap(x);\n        assertEq(actual, expected, \"SD21x18 unwrap\");\n    }\n\n    function testFuzz_Wrap(int128 x) external pure {\n        SD21x18 actual = wrap(x);\n        SD21x18 expected = SD21x18.wrap(x);\n        assertEq(actual, expected, \"SD21x18 wrap\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/sd59x18/casting/Casting.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { uMAX_SD1x18, uMIN_SD1x18 } from \"src/sd1x18/Constants.sol\";\nimport { SD1x18 } from \"src/sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18, uMIN_SD21x18 } from \"src/sd21x18/Constants.sol\";\nimport { SD21x18 } from \"src/sd21x18/ValueType.sol\";\nimport { sd, sd59x18, wrap } from \"src/sd59x18/Casting.sol\";\nimport { MAX_SD59x18, MIN_SD59x18 } from \"src/sd59x18/Constants.sol\";\nimport {\n    PRBMath_SD59x18_IntoSD1x18_Overflow,\n    PRBMath_SD59x18_IntoSD1x18_Underflow,\n    PRBMath_SD59x18_IntoSD21x18_Overflow,\n    PRBMath_SD59x18_IntoSD21x18_Underflow,\n    PRBMath_SD59x18_IntoUD60x18_Underflow,\n    PRBMath_SD59x18_IntoUint256_Underflow,\n    PRBMath_SD59x18_IntoUD2x18_Overflow,\n    PRBMath_SD59x18_IntoUD2x18_Underflow,\n    PRBMath_SD59x18_IntoUD21x18_Overflow,\n    PRBMath_SD59x18_IntoUD21x18_Underflow,\n    PRBMath_SD59x18_IntoUint128_Overflow,\n    PRBMath_SD59x18_IntoUint128_Underflow,\n    PRBMath_SD59x18_IntoUint40_Overflow,\n    PRBMath_SD59x18_IntoUint40_Underflow\n} from \"src/sd59x18/Errors.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"src/ud2x18/Constants.sol\";\nimport { UD2x18 } from \"src/ud2x18/ValueType.sol\";\nimport { uMAX_UD21x18 } from \"src/ud21x18/Constants.sol\";\nimport { UD21x18 } from \"src/ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting functions available in SD59x18.\ncontract SD59x18_Casting_Fuzz_Test is Base_Test {\n    function testFuzz_IntoInt256(SD59x18 x) external pure {\n        int256 actual = x.intoInt256();\n        int256 expected = SD59x18.unwrap(x);\n        assertEq(actual, expected, \"SD59x18 intoInt256\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowSD1x18(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, int256(uMIN_SD1x18) - 1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoSD1x18_Underflow.selector, x));\n        x.intoSD1x18();\n    }\n\n    function testFuzz_RevertWhen_OverflowSD1x18(SD59x18 x) external {\n        x = _bound(x, int256(uMAX_SD1x18) + 1, MAX_SD59x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoSD1x18_Overflow.selector, x));\n        x.intoSD1x18();\n    }\n\n    function testFuzz_IntoSD1x18(SD59x18 x) external pure {\n        x = _bound(x, uMIN_SD1x18, uMAX_SD1x18);\n        SD1x18 actual = x.intoSD1x18();\n        SD1x18 expected = SD1x18.wrap(int64(x.unwrap()));\n        assertEq(actual, expected, \"SD59x18 intoSD1x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowSD21x18(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, int256(uMIN_SD21x18) - 1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoSD21x18_Underflow.selector, x));\n        x.intoSD21x18();\n    }\n\n    function testFuzz_RevertWhen_OverflowSD21x18(SD59x18 x) external {\n        x = _bound(x, int256(uMAX_SD21x18) + 1, MAX_SD59x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoSD21x18_Overflow.selector, x));\n        x.intoSD21x18();\n    }\n\n    function testFuzz_IntoSD21x18(SD59x18 x) external pure {\n        x = _bound(x, uMIN_SD21x18, uMAX_SD21x18);\n        SD21x18 actual = x.intoSD21x18();\n        SD21x18 expected = SD21x18.wrap(int128(x.unwrap()));\n        assertEq(actual, expected, \"SD59x18 intoSD21x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUD2x18(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUD2x18_Underflow.selector, x));\n        x.intoUD2x18();\n    }\n\n    function testFuzz_RevertWhen_OverflowUD2x18(SD59x18 x) external {\n        x = _bound(x, int256(uint256(uMAX_UD2x18)) + 1, MAX_SD59x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUD2x18_Overflow.selector, x));\n        x.intoUD2x18();\n    }\n\n    function testFuzz_IntoUD2x18(SD59x18 x) external pure {\n        x = _bound(x, 0, int256(uint256(uMAX_UD2x18)));\n        UD2x18 actual = x.intoUD2x18();\n        UD2x18 expected = UD2x18.wrap(uint64(uint256(x.unwrap())));\n        assertEq(actual, expected, \"SD59x18 intoUD2x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUD21x18(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUD21x18_Underflow.selector, x));\n        x.intoUD21x18();\n    }\n\n    function testFuzz_RevertWhen_OverflowUD21x18(SD59x18 x) external {\n        x = _bound(x, int256(uint256(uMAX_UD21x18)) + 1, MAX_SD59x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUD21x18_Overflow.selector, x));\n        x.intoUD21x18();\n    }\n\n    function testFuzz_IntoUD21x18(SD59x18 x) external pure {\n        x = _bound(x, 0, int256(uint256(uMAX_UD21x18)));\n        UD21x18 actual = x.intoUD21x18();\n        UD21x18 expected = UD21x18.wrap(uint128(uint256(x.unwrap())));\n        assertEq(actual, expected, \"SD59x18 intoUD21x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUD60x18(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUD60x18_Underflow.selector, x));\n        x.intoUD60x18();\n    }\n\n    function testFuzz_IntoUD60x18(SD59x18 x) external pure {\n        x = _bound(x, 0, MAX_SD59x18);\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(uint256(x.unwrap()));\n        assertEq(actual, expected, \"SD59x18 intoUD60x18\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint128(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUint128_Underflow.selector, x));\n        x.intoUint128();\n    }\n\n    function testFuzz_RevertWhen_OverflowUint128(SD59x18 x) external {\n        x = _bound(x, int256(uint256(MAX_UINT128)) + 1, MAX_SD59x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUint128_Overflow.selector, x));\n        x.intoUint128();\n    }\n\n    function testFuzz_IntoUint128(SD59x18 x) external pure {\n        x = _bound(x, 0, int256(uint256(MAX_UINT128)));\n        uint128 actual = x.intoUint128();\n        uint128 expected = uint128(uint256(x.unwrap()));\n        assertEq(actual, expected, \"SD59x18 intoUint128\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint256(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUint256_Underflow.selector, x));\n        x.intoUint256();\n    }\n\n    function testFuzz_IntoUint256(SD59x18 x) external pure {\n        x = _bound(x, 0, MAX_SD59x18);\n        uint256 actual = x.intoUint256();\n        uint256 expected = uint256(x.unwrap());\n        assertEq(actual, expected, \"SD59x18 intoUint256\");\n    }\n\n    function testFuzz_RevertWhen_UnderflowUint40(SD59x18 x) external {\n        x = _bound(x, MIN_SD59x18, -1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUint40_Underflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_RevertWhen_OverflowUint40(SD59x18 x) external {\n        x = _bound(x, int256(uint256(MAX_UINT40)) + 1, MAX_SD59x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_IntoUint40_Overflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_IntoUint40(SD59x18 x) external pure {\n        x = _bound(x, 0, int256(uint256(MAX_UINT40)));\n        uint40 actual = x.intoUint40();\n        uint40 expected = uint40(uint256(x.unwrap()));\n        assertEq(actual, expected, \"SD59x18 intoUint40\");\n    }\n\n    function testFuzz_Sd(int256 x) external pure {\n        SD59x18 actual = sd(x);\n        SD59x18 expected = SD59x18.wrap(x);\n        assertEq(actual, expected, \"sd\");\n    }\n\n    function testFuzz_sd59x18(int256 x) external pure {\n        SD59x18 actual = sd59x18(x);\n        SD59x18 expected = SD59x18.wrap(x);\n        assertEq(actual, expected, \"sd59x18\");\n    }\n\n    function testFuzz_Unwrap(SD59x18 x) external pure {\n        int256 actual = x.unwrap();\n        int256 expected = SD59x18.unwrap(x);\n        assertEq(actual, expected, \"SD59x18 unwrap\");\n    }\n\n    function testFuzz_Wrap(int256 x) external pure {\n        SD59x18 actual = wrap(x);\n        SD59x18 expected = SD59x18.wrap(x);\n        assertEq(actual, expected, \"SD59x18 wrap\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/sd59x18/helpers/Helpers.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport {\n    add,\n    and,\n    eq,\n    gt,\n    gte,\n    isZero,\n    lshift,\n    lt,\n    lte,\n    mod,\n    neq,\n    or,\n    rshift,\n    sub,\n    unary,\n    uncheckedAdd,\n    uncheckedSub,\n    xor,\n    not\n} from \"src/sd59x18/Helpers.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the helpers functions available in the SD59x18 type.\ncontract SD59x18_Helpers_Fuzz_Test is Base_Test {\n    int256 internal constant HALF_MAX_INT256 = MAX_INT256 / 2;\n    int256 internal constant HALF_MIN_INT256 = MIN_INT256 / 2;\n\n    function testFuzz_Add(SD59x18 x, SD59x18 y) external pure {\n        x = _bound(x, HALF_MIN_INT256, HALF_MAX_INT256);\n        y = _bound(y, HALF_MIN_INT256, HALF_MAX_INT256);\n        SD59x18 expected = sd(x.unwrap() + y.unwrap());\n        assertEq(add(x, y), expected, \"SD59x18 add\");\n        assertEq(x + y, expected, \"SD59x18 +\");\n    }\n\n    function testFuzz_And(int256 x, int256 y) external pure {\n        SD59x18 expected = sd(x & y);\n        assertEq(and(sd(x), y), expected, \"SD59x18 and\");\n        assertEq(sd(x) & sd(y), expected, \"SD59x18 &\");\n    }\n\n    function testFuzz_Eq(int256 x) external pure {\n        int256 y = x;\n        assertTrue(eq(sd(x), sd(y)), \"SD59x18 eq\");\n        assertTrue(sd(x) == sd(y), \"SD59x18 ==\");\n    }\n\n    function testFuzz_Gt(int256 x, int256 y) external pure {\n        vm.assume(x > y);\n        assertTrue(gt(sd(x), sd(y)), \"SD59x18 gt\");\n        assertTrue(sd(x) > sd(y), \"SD59x18 >\");\n    }\n\n    function testFuzz_Gte(int256 x, int256 y) external pure {\n        vm.assume(x >= y);\n        assertTrue(gte(sd(x), sd(y)), \"SD59x18 gte\");\n        assertTrue(sd(x) >= sd(y), \"SD59x18 >=\");\n    }\n\n    function testFuzz_IsZero(SD59x18 x) external pure {\n        bool actual = isZero(x);\n        bool expected = x == sd(0);\n        assertEq(actual, expected, \"SD59x18 isZero\");\n    }\n\n    function testFuzz_Lshift(int256 x, uint256 y) external pure {\n        _bound(y, 0, 512);\n        SD59x18 expected = sd(x << y);\n        assertEq(lshift(sd(x), y), expected, \"SD59x18 lshift\");\n    }\n\n    function testFuzz_Lt(int256 x, int256 y) external pure {\n        vm.assume(x < y);\n        assertTrue(lt(sd(x), sd(y)), \"SD59x18 lt\");\n        assertTrue(sd(x) < sd(y), \"SD59x18 <\");\n    }\n\n    function testFuzz_Lte(int256 x, int256 y) external pure {\n        vm.assume(x <= y);\n        assertTrue(lte(sd(x), sd(y)), \"SD59x18 lte\");\n        assertTrue(sd(x) <= sd(y), \"SD59x18 <=\");\n    }\n\n    function testFuzz_Mod(int256 x, int256 y) external pure {\n        vm.assume(y != 0);\n        SD59x18 expected = sd(x % y);\n        assertEq(mod(sd(x), sd(y)), expected, \"SD59x18 mod\");\n        assertEq(sd(x) % sd(y), expected, \"SD59x18 %\");\n    }\n\n    function testFuzz_Neq(int256 x, int256 y) external pure {\n        vm.assume(x != y);\n        assertTrue(neq(sd(x), sd(y)), \"SD59x18 neq\");\n        assertTrue(sd(x) != sd(y), \"SD59x18 !=\");\n    }\n\n    function testFuzz_Not(int256 x) external pure {\n        SD59x18 expected = sd(~x);\n        assertEq(not(sd(x)), expected, \"SD59x18 not\");\n        assertEq(~sd(x), expected, \"SD59x18 ~\");\n    }\n\n    function testFuzz_Or(int256 x, int256 y) external pure {\n        SD59x18 expected = sd(x | y);\n        assertEq(or(sd(x), sd(y)), expected, \"SD59x18 or\");\n        assertEq(sd(x) | sd(y), expected, \"SD59x18 |\");\n    }\n\n    function testFuzz_Rshift(int256 x, uint256 y) external pure {\n        _bound(y, 0, 512);\n        SD59x18 expected = sd(x >> y);\n        assertEq(rshift(sd(x), y), expected, \"SD59x18 rshift\");\n    }\n\n    function testFuzz_Sub(SD59x18 x, SD59x18 y) external pure {\n        x = _bound(x, HALF_MIN_INT256, HALF_MAX_INT256);\n        y = _bound(y, HALF_MIN_INT256, HALF_MAX_INT256);\n        SD59x18 expected = sd(x.unwrap() - y.unwrap());\n        assertEq(sub(x, y), expected, \"SD59x18 sub\");\n        assertEq(x - y, expected, \"SD59x18 -\");\n    }\n\n    function testFuzz_Unary(int256 x) external pure {\n        // Cannot take unary of MIN_INT256, because its absolute value would be 1 unit larger than MAX_INT256.\n        x = _bound(x, MIN_INT256 + 1, MAX_INT256);\n        SD59x18 expected = sd(-x);\n        assertEq(unary(sd(x)), expected, \"SD59x18 unary\");\n        assertEq(-sd(x), expected, \"SD59x18 -\");\n    }\n\n    function testFuzz_UncheckedAdd(int256 x, int256 y) external pure {\n        unchecked {\n            SD59x18 expected = sd(x + y);\n            SD59x18 actual = uncheckedAdd(sd(x), sd(y));\n            assertEq(actual, expected, \"SD59x18 uncheckedAdd\");\n        }\n    }\n\n    function testFuzz_UncheckedSub(int256 x, int256 y) external pure {\n        unchecked {\n            SD59x18 expected = sd(x - y);\n            SD59x18 actual = uncheckedSub(sd(x), sd(y));\n            assertEq(actual, expected, \"SD59x18 uncheckedSub\");\n        }\n    }\n\n    function testFuzz_Xor(int256 x, int256 y) external pure {\n        SD59x18 expected = sd(x ^ y);\n        assertEq(xor(sd(x), sd(y)), expected, \"SD59x18 xor\");\n        assertEq(sd(x) ^ sd(y), expected, \"SD59x18 ^\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/sd59x18/math/pow/pow.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { UNIT, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { pow } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../../Base.t.sol\";\n\ncontract Pow_Fuzz_Test is Base_Test {\n    function testFuzz_Pow_BaseZero_ExponentNotZero(SD59x18 y) external pure {\n        vm.assume(y != ZERO);\n        SD59x18 x = ZERO;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    modifier whenBaseNotZero() {\n        _;\n    }\n\n    function testFuzz_Pow_BaseUnit(SD59x18 y) external pure whenBaseNotZero {\n        SD59x18 x = UNIT;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = UNIT;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    modifier whenBaseNotUnit() {\n        _;\n    }\n\n    function testFuzz_Pow_ExponentZero(SD59x18 x) external pure whenBaseNotZero whenBaseNotUnit {\n        vm.assume(x != ZERO && x != UNIT);\n        SD59x18 y = ZERO;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = UNIT;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    modifier whenExponentNotZero() {\n        _;\n    }\n\n    function testFuzz_Pow_ExponentUnit(SD59x18 x) external pure whenBaseNotZero whenBaseNotUnit whenExponentNotZero {\n        vm.assume(x != ZERO && x != UNIT);\n        SD59x18 y = UNIT;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = x;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/ud21x18/casting/Casting.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { ud21x18, wrap } from \"src/ud21x18/Casting.sol\";\nimport { uMAX_UD21x18 } from \"src/ud21x18/Constants.sol\";\nimport { PRBMath_UD21x18_IntoUint40_Overflow } from \"src/ud21x18/Errors.sol\";\nimport { UD21x18 } from \"src/ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting functions available in UD21x18.\ncontract UD21x18_Casting_Fuzz_Test is Base_Test {\n    function testFuzz_IntoSD59x18(UD21x18 x) external pure {\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(uint256(x.unwrap())));\n        assertEq(actual, expected, \"UD21x18 intoSD59x18\");\n    }\n\n    function testFuzz_IntoUD60x18(UD21x18 x) external pure {\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(uint256(x.unwrap()));\n        assertEq(actual, expected, \"UD21x18 intoUD60x18\");\n    }\n\n    function testFuzz_intoUint128(UD21x18 x) external pure {\n        uint128 actual = x.intoUint128();\n        uint128 expected = x.unwrap();\n        assertEq(actual, expected, \"UD21x18 intoUint128\");\n    }\n\n    function testFuzz_IntoUint256(UD21x18 x) external pure {\n        uint256 actual = x.intoUint256();\n        uint256 expected = uint256(x.unwrap());\n        assertEq(actual, expected, \"UD21x18 intoUint256\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUint40(UD21x18 x) external {\n        x = _bound(x, uint128(MAX_UINT40) + 1, uMAX_UD21x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD21x18_IntoUint40_Overflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_IntoUint40(UD21x18 x) external pure {\n        x = _bound(x, 0, uint128(MAX_UINT40));\n        uint40 actual = x.intoUint40();\n        uint40 expected = uint40(x.unwrap());\n        assertEq(actual, expected, \"UD21x18 intoUint40\");\n    }\n\n    function testFuzz_ud21x18(uint128 x) external pure {\n        UD21x18 actual = ud21x18(x);\n        UD21x18 expected = UD21x18.wrap(x);\n        assertEq(actual, expected, \"ud21x18\");\n    }\n\n    function testFuzz_Unwrap(UD21x18 x) external pure {\n        uint128 actual = x.unwrap();\n        uint128 expected = UD21x18.unwrap(x);\n        assertEq(actual, expected, \"UD21x18 unwrap\");\n    }\n\n    function testFuzz_Wrap(uint128 x) external pure {\n        UD21x18 actual = wrap(x);\n        UD21x18 expected = UD21x18.wrap(x);\n        assertEq(actual, expected, \"UD21x18 wrap\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/ud2x18/casting/Casting.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { ud2x18, wrap } from \"src/ud2x18/Casting.sol\";\nimport { uMAX_UD2x18 } from \"src/ud2x18/Constants.sol\";\nimport { PRBMath_UD2x18_IntoUint40_Overflow } from \"src/ud2x18/Errors.sol\";\nimport { UD2x18 } from \"src/ud2x18/ValueType.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting functions available in UD2x18.\ncontract UD2x18_Casting_Fuzz_Test is Base_Test {\n    function testFuzz_IntoSD59x18(UD2x18 x) external pure {\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(uint256(x.unwrap())));\n        assertEq(actual, expected, \"UD2x18 intoSD59x18\");\n    }\n\n    function testFuzz_IntoUD60x18(UD2x18 x) external pure {\n        UD60x18 actual = x.intoUD60x18();\n        UD60x18 expected = UD60x18.wrap(uint256(x.unwrap()));\n        assertEq(actual, expected, \"UD2x18 intoUD60x18\");\n    }\n\n    function testFuzz_IntoUint128(UD2x18 x) external pure {\n        uint128 actual = x.intoUint128();\n        uint128 expected = uint128(x.unwrap());\n        assertEq(actual, expected, \"UD2x18 intoUint128\");\n    }\n\n    function testFuzz_IntoUint256(UD2x18 x) external pure {\n        uint256 actual = x.intoUint256();\n        uint256 expected = uint256(x.unwrap());\n        assertEq(actual, expected, \"UD2x18 intoUint256\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUint40(UD2x18 x) external {\n        x = _bound(x, uint64(MAX_UINT40) + 1, uMAX_UD2x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD2x18_IntoUint40_Overflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_IntoUint40(UD2x18 x) external pure {\n        x = _bound(x, 0, uint64(MAX_UINT40));\n        uint40 actual = x.intoUint40();\n        uint40 expected = uint40(x.unwrap());\n        assertEq(actual, expected, \"UD2x18 intoUint40\");\n    }\n\n    function testFuzz_ud2x18(uint64 x) external pure {\n        UD2x18 actual = ud2x18(x);\n        UD2x18 expected = UD2x18.wrap(x);\n        assertEq(actual, expected, \"ud2x18\");\n    }\n\n    function testFuzz_Unwrap(UD2x18 x) external pure {\n        uint64 actual = x.unwrap();\n        uint64 expected = UD2x18.unwrap(x);\n        assertEq(actual, expected, \"UD2x18 unwrap\");\n    }\n\n    function testFuzz_Wrap(uint64 x) external pure {\n        UD2x18 actual = wrap(x);\n        UD2x18 expected = UD2x18.wrap(x);\n        assertEq(actual, expected, \"UD2x18 wrap\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/ud60x18/casting/Casting.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { uMAX_SD1x18 } from \"src/sd1x18/Constants.sol\";\nimport { SD1x18 } from \"src/sd1x18/ValueType.sol\";\nimport { uMAX_SD21x18 } from \"src/sd21x18/Constants.sol\";\nimport { SD21x18 } from \"src/sd21x18/ValueType.sol\";\nimport { uMAX_SD59x18 } from \"src/sd59x18/Constants.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { uMAX_UD2x18 } from \"src/ud2x18/Constants.sol\";\nimport { uMAX_UD21x18 } from \"src/ud21x18/Constants.sol\";\nimport { UD2x18 } from \"src/ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"src/ud21x18/ValueType.sol\";\nimport { ud, ud60x18, wrap } from \"src/ud60x18/Casting.sol\";\nimport { MAX_UD60x18 } from \"src/ud60x18/Constants.sol\";\nimport {\n    PRBMath_UD60x18_IntoSD1x18_Overflow,\n    PRBMath_UD60x18_IntoSD21x18_Overflow,\n    PRBMath_UD60x18_IntoSD59x18_Overflow,\n    PRBMath_UD60x18_IntoUD2x18_Overflow,\n    PRBMath_UD60x18_IntoUint128_Overflow,\n    PRBMath_UD60x18_IntoUint40_Overflow\n} from \"src/ud60x18/Errors.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the casting functions available in UD60x18.\ncontract UD60x18_Casting_Fuzz_Test is Base_Test {\n    function testFuzz_RevertWhen_OverflowSD1x18(UD60x18 x) external {\n        x = _bound(x, ud(uint64(uMAX_SD1x18) + 1), MAX_UD60x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_IntoSD1x18_Overflow.selector, x));\n        x.intoSD1x18();\n    }\n\n    function testFuzz_intoSD1x18(UD60x18 x) external pure {\n        x = _bound(x, 0, ud(uint64(uMAX_SD1x18)));\n        SD1x18 actual = x.intoSD1x18();\n        SD1x18 expected = SD1x18.wrap(int64(uint64(x.unwrap())));\n        assertEq(actual, expected, \"UD60x18 intoSD1x18\");\n    }\n\n    function testFuzz_RevertWhen_OverflowSD21x18(UD60x18 x) external {\n        x = _bound(x, ud(uint128(uMAX_SD21x18) + 1), MAX_UD60x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_IntoSD21x18_Overflow.selector, x));\n        x.intoSD21x18();\n    }\n\n    function testFuzz_intoSD21x18(UD60x18 x) external pure {\n        x = _bound(x, 0, ud(uint128(uMAX_SD21x18)));\n        SD21x18 actual = x.intoSD21x18();\n        SD21x18 expected = SD21x18.wrap(int128(uint128(x.unwrap())));\n        assertEq(actual, expected, \"UD60x18 intoSD21x18\");\n    }\n\n    function testFuzz_RevertWhen_OverflowSD59x18(UD60x18 x) external {\n        x = _bound(x, ud(uint256(uMAX_SD59x18) + 1), MAX_UD60x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_IntoSD59x18_Overflow.selector, x));\n        x.intoSD59x18();\n    }\n\n    function testFuzz_intoSD59x18(UD60x18 x) external pure {\n        x = _bound(x, 0, ud(uint256(uMAX_SD59x18)));\n        SD59x18 actual = x.intoSD59x18();\n        SD59x18 expected = SD59x18.wrap(int256(uint256(x.unwrap())));\n        assertEq(actual, expected, \"UD60x18 intoSD59x18\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUD2x18(UD60x18 x) external {\n        x = _bound(x, ud(uint256(uMAX_UD2x18) + 1), MAX_UD60x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_IntoUD2x18_Overflow.selector, x));\n        x.intoUD2x18();\n    }\n\n    function testFuzz_intoUD2x18(UD60x18 x) external pure {\n        x = _bound(x, 0, ud(uint256(uMAX_UD2x18)));\n        UD2x18 actual = x.intoUD2x18();\n        UD2x18 expected = UD2x18.wrap(uint64(x.unwrap()));\n        assertEq(actual, expected, \"UD60x18 intoUD2x18\");\n    }\n\n    function testFuzz_intoUD21x18(UD60x18 x) external pure {\n        x = _bound(x, 0, ud(uint256(uMAX_UD21x18)));\n        UD21x18 actual = x.intoUD21x18();\n        UD21x18 expected = UD21x18.wrap(uint128(x.unwrap()));\n        assertEq(actual, expected, \"UD60x18 intoUD21x18\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUint128(UD60x18 x) external {\n        x = _bound(x, ud(uint256(MAX_UINT128) + 1), MAX_UD60x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_IntoUint128_Overflow.selector, x));\n        x.intoUint128();\n    }\n\n    function testFuzz_intoUint128(UD60x18 x) external pure {\n        x = _bound(x, 0, ud(uint256(MAX_UINT128)));\n        uint128 actual = x.intoUint128();\n        uint128 expected = uint128(x.unwrap());\n        assertEq(actual, expected, \"UD60x18 intoUint128\");\n    }\n\n    function testFuzz_intoUint256(UD60x18 x) external pure {\n        uint256 actual = x.intoUint256();\n        uint256 expected = x.unwrap();\n        assertEq(actual, expected, \"UD60x18 intoUint256\");\n    }\n\n    function testFuzz_RevertWhen_OverflowUint40(UD60x18 x) external {\n        x = _bound(x, ud(uint256(MAX_UINT40) + 1), MAX_UD60x18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_IntoUint40_Overflow.selector, x));\n        x.intoUint40();\n    }\n\n    function testFuzz_intoUint40(UD60x18 x) external pure {\n        x = _bound(x, 0, ud(uint256(MAX_UINT40)));\n        uint40 actual = uint40(x.intoUint40());\n        uint40 expected = uint40(x.unwrap());\n        assertEq(actual, expected, \"UD60x18 intoUint40\");\n    }\n\n    function testFuzz_Ud(uint256 x) external pure {\n        UD60x18 actual = ud(x);\n        UD60x18 expected = UD60x18.wrap(x);\n        assertEq(actual, expected, \"ud\");\n    }\n\n    function testFuzz_UD60x18(uint256 x) external pure {\n        UD60x18 actual = ud60x18(x);\n        UD60x18 expected = UD60x18.wrap(x);\n        assertEq(actual, expected, \"ud60x18\");\n    }\n\n    function testFuzz_Unwrap(UD60x18 x) external pure {\n        uint256 actual = x.unwrap();\n        uint256 expected = UD60x18.unwrap(x);\n        assertEq(actual, expected, \"UD60x18 unwrap\");\n    }\n\n    function testFuzz_Wrap(uint256 x) external pure {\n        UD60x18 actual = wrap(x);\n        UD60x18 expected = UD60x18.wrap(x);\n        assertEq(actual, expected, \"UD60x18 wrap\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/ud60x18/helpers/Helpers.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { ud } from \"src/ud60x18/Casting.sol\";\nimport {\n    add,\n    and,\n    eq,\n    gt,\n    gte,\n    isZero,\n    lshift,\n    lt,\n    lte,\n    mod,\n    neq,\n    or,\n    rshift,\n    sub,\n    uncheckedAdd,\n    uncheckedSub,\n    xor,\n    not\n} from \"src/ud60x18/Helpers.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../Base.t.sol\";\n\n/// @dev Collection of tests for the helpers functions available in the UD60x18 type.\ncontract UD60x18_Helpers_Fuzz_Test is Base_Test {\n    uint256 internal constant HALF_MAX_UINT256 = type(uint256).max / 2;\n\n    function testFuzz_Add(UD60x18 x, UD60x18 y) external pure {\n        x = _bound(x, 0, HALF_MAX_UINT256);\n        y = _bound(y, 0, HALF_MAX_UINT256);\n        UD60x18 expected = ud(x.unwrap() + y.unwrap());\n        assertEq(add(x, y), expected, \"UD60x18 add\");\n        assertEq(x + y, expected, \"UD60x18 +\");\n    }\n\n    function testFuzz_And(uint256 x, uint256 y) external pure {\n        UD60x18 expected = ud(x & y);\n        assertEq(and(ud(x), y), expected, \"UD60x18 and\");\n        assertEq(ud(x) & ud(y), expected, \"UD60x18 &\");\n    }\n\n    function testFuzz_Eq(uint256 x) external pure {\n        uint256 y = x;\n        assertTrue(eq(ud(x), ud(y)), \"UD60x18 eq\");\n        assertTrue(ud(x) == ud(y), \"UD60x18 ==\");\n    }\n\n    function testFuzz_Gt(uint256 x, uint256 y) external pure {\n        vm.assume(x > y);\n        assertTrue(gt(ud(x), ud(y)), \"UD60x18 gt\");\n        assertTrue(ud(x) > ud(y), \"UD60x18 >\");\n    }\n\n    function testFuzz_Gte(uint256 x, uint256 y) external pure {\n        vm.assume(x >= y);\n        assertTrue(gte(ud(x), ud(y)), \"UD60x18 gte\");\n        assertTrue(ud(x) >= ud(y), \"UD60x18 >=\");\n    }\n\n    function testFuzz_IsZero(UD60x18 x) external pure {\n        bool actual = isZero(x);\n        bool expected = x == ud(0);\n        assertEq(actual, expected, \"SD59x18 isZero\");\n    }\n\n    function testFuzz_Lshift(uint256 x, uint256 y) external pure {\n        y = _bound(y, 0, 512);\n        UD60x18 expected = ud(x << y);\n        assertEq(lshift(ud(x), y), expected, \"UD60x18 lshift\");\n    }\n\n    function testFuzz_Lt(uint256 x, uint256 y) external pure {\n        vm.assume(x < y);\n        assertTrue(lt(ud(x), ud(y)), \"UD60x18 lt\");\n        assertTrue(ud(x) < ud(y), \"UD60x18 <\");\n    }\n\n    function testFuzz_Lte(uint256 x, uint256 y) external pure {\n        vm.assume(x <= y);\n        assertTrue(lte(ud(x), ud(y)), \"UD60x18 lte\");\n        assertTrue(ud(x) <= ud(y), \"UD60x18 <=\");\n    }\n\n    function testFuzz_Mod(uint256 x, uint256 y) external pure {\n        vm.assume(y > 0);\n        UD60x18 expected = ud(x % y);\n        assertEq(mod(ud(x), ud(y)), expected, \"UD60x18 mod\");\n        assertEq(ud(x) % ud(y), expected, \"UD60x18 %\");\n    }\n\n    function testFuzz_Neq(uint256 x, uint256 y) external pure {\n        vm.assume(x != y);\n        assertTrue(neq(ud(x), ud(y)), \"UD60x18 neq\");\n        assertTrue(ud(x) != ud(y), \"UD60x18 !=\");\n    }\n\n    function testFuzz_Not(uint256 x) external pure {\n        UD60x18 expected = ud(~x);\n        assertEq(not(ud(x)), expected, \"UD60x18 not\");\n        assertEq(~ud(x), expected, \"UD60x18 ~\");\n    }\n\n    function testFuzz_Or(uint256 x, uint256 y) external pure {\n        UD60x18 expected = ud(x | y);\n        assertEq(or(ud(x), ud(y)), expected, \"UD60x18 or\");\n        assertEq(ud(x) | ud(y), expected, \"UD60x18 |\");\n    }\n\n    function testFuzz_Rshift(uint256 x, uint256 y) external pure {\n        y = _bound(y, 0, 512);\n        UD60x18 expected = ud(x >> y);\n        assertEq(rshift(ud(x), y), expected, \"UD60x18 rshift\");\n    }\n\n    function testFuzz_Sub(uint256 x, uint256 y) external pure {\n        vm.assume(x >= y);\n        UD60x18 expected = ud(x - y);\n        assertEq(sub(ud(x), ud(y)), expected, \"UD60x18 sub\");\n        assertEq(ud(x) - ud(y), expected, \"UD60x18 -\");\n    }\n\n    function testFuzz_UncheckedAdd(uint256 x, uint256 y) external pure {\n        unchecked {\n            UD60x18 expected = ud(x + y);\n            UD60x18 actual = uncheckedAdd(ud(x), ud(y));\n            assertEq(actual, expected, \"UD60x18 uncheckedAdd\");\n        }\n    }\n\n    function testFuzz_UncheckedSub(uint256 x, uint256 y) external pure {\n        unchecked {\n            UD60x18 expected = ud(x - y);\n            UD60x18 actual = uncheckedSub(ud(x), ud(y));\n            assertEq(actual, expected, \"UD60x18 uncheckedSub\");\n        }\n    }\n\n    function testFuzz_Xor(uint256 x, uint256 y) external pure {\n        UD60x18 expected = ud(x ^ y);\n        assertEq(xor(ud(x), ud(y)), expected, \"UD60x18 xor\");\n        assertEq(ud(x) ^ ud(y), expected, \"UD60x18 ^\");\n    }\n}\n"
  },
  {
    "path": "test/fuzz/ud60x18/math/pow/pow.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { UNIT, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { pow } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../../../Base.t.sol\";\n\ncontract Pow_Fuzz_Test is Base_Test {\n    function testFuzz_Pow_BaseZero_ExponentNotZero(UD60x18 y) external pure {\n        vm.assume(y != ZERO);\n        UD60x18 x = ZERO;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = ZERO;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    modifier whenBaseNotZero() {\n        _;\n    }\n\n    function testFuzz_Pow_BaseUnit(UD60x18 y) external pure whenBaseNotZero {\n        UD60x18 x = UNIT;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = UNIT;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    modifier whenBaseNotUnit() {\n        _;\n    }\n\n    function testFuzz_Pow_ExponentZero(UD60x18 x) external pure whenBaseNotZero whenBaseNotUnit {\n        vm.assume(x != ZERO && x != UNIT);\n        UD60x18 y = ZERO;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = UNIT;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    modifier whenExponentNotZero() {\n        _;\n    }\n\n    function testFuzz_Pow_ExponentUnit(UD60x18 x) external pure whenBaseNotZero whenBaseNotUnit whenExponentNotZero {\n        vm.assume(x != ZERO && x != UNIT);\n        UD60x18 y = UNIT;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = x;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/SD59x18.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { console2 } from \"forge-std/src/console2.sol\";\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { ZERO } from \"src/sd59x18/Constants.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\nimport { Base_Test } from \"../../Base.t.sol\";\n\n/// @notice Common logic needed by all SD59x18 unit tests.\nabstract contract SD59x18_Unit_Test is Base_Test {\n    /*//////////////////////////////////////////////////////////////////////////\n                                      CONSTANTS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    SD59x18 internal constant MAX_SCALED_SD59x18 = SD59x18.wrap(57896044618658097711785492504343953926634_992332820282019728);\n    SD59x18 internal constant MIN_SCALED_SD59x18 = SD59x18.wrap(-57896044618658097711785492504343953926634_992332820282019728);\n    SD59x18 internal constant NEGATIVE_E = SD59x18.wrap(-2_718281828459045235);\n    SD59x18 internal constant NEGATIVE_PI = SD59x18.wrap(-3_141592653589793238);\n    SD59x18 internal constant SQRT_MAX_SD59x18 = SD59x18.wrap(240615969168004511545033772477_625056927114980741);\n    SD59x18 internal constant SQRT_MAX_UD60x18 = SD59x18.wrap(340282366920938463463374607431_768211455999999999);\n    SD59x18 internal constant NEGATIVE_SQRT_MAX_SD59x18 = SD59x18.wrap(-240615969168004511545033772477_625056927114980741);\n    SD59x18 internal constant NEGATIVE_SQRT_MAX_UD60x18 = SD59x18.wrap(-340282366920938463463374607431_768211455999999999);\n\n    /// @dev This is needed to be passed as the \"expected\" argument. The \"set\" function cannot be overridden\n    /// to have two implementations that each has two \"int256\" arguments.\n    SD59x18 internal constant NIL = ZERO;\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                       STRUCTS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    struct Set {\n        SD59x18 x;\n        SD59x18 y;\n        SD59x18 expected;\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                     VARIABLES\n    //////////////////////////////////////////////////////////////////////////*/\n\n    Set internal s;\n    Set[] internal sets;\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                      MODIFIERS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    modifier parameterizedTest(Set[] memory testSets) {\n        uint256 length = testSets.length;\n        for (uint256 i = 0; i < length; ++i) {\n            s = testSets[i];\n            _;\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                              CONSTANT HELPER FUNCTIONS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function logSd(SD59x18 p0) internal pure {\n        console2.logInt(p0.unwrap());\n    }\n\n    function sdToUint(SD59x18 x) internal pure returns (uint256 result) {\n        result = uint256(x.unwrap());\n    }\n\n    function set(int256 x) internal pure returns (Set memory) {\n        return Set({ x: sd(x), y: ZERO, expected: ZERO });\n    }\n\n    function set(SD59x18 x) internal pure returns (Set memory) {\n        return Set({ x: x, y: ZERO, expected: ZERO });\n    }\n\n    function set(int256 x, int256 expected) internal pure returns (Set memory) {\n        return Set({ x: sd(x), y: ZERO, expected: sd(expected) });\n    }\n\n    function set(int256 x, SD59x18 expected) internal pure returns (Set memory) {\n        return Set({ x: sd(x), y: ZERO, expected: expected });\n    }\n\n    function set(SD59x18 x, int256 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: ZERO, expected: sd(expected) });\n    }\n\n    function set(SD59x18 x, SD59x18 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: ZERO, expected: expected });\n    }\n\n    function set(int256 x, int256 y, int256 expected) internal pure returns (Set memory) {\n        return Set({ x: sd(x), y: sd(y), expected: sd(expected) });\n    }\n\n    function set(int256 x, int256 y, SD59x18 expected) internal pure returns (Set memory) {\n        return Set({ x: sd(x), y: sd(y), expected: expected });\n    }\n\n    function set(int256 x, SD59x18 y, int256 expected) internal pure returns (Set memory) {\n        return Set({ x: sd(x), y: y, expected: sd(expected) });\n    }\n\n    function set(int256 x, SD59x18 y, SD59x18 expected) internal pure returns (Set memory) {\n        return Set({ x: sd(x), y: y, expected: expected });\n    }\n\n    function set(SD59x18 x, int256 y, int256 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: sd(y), expected: sd(expected) });\n    }\n\n    function set(SD59x18 x, SD59x18 y, int256 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: y, expected: sd(expected) });\n    }\n\n    function set(SD59x18 x, int256 y, SD59x18 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: sd(y), expected: expected });\n    }\n\n    function set(SD59x18 x, SD59x18 y, SD59x18 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: y, expected: expected });\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/conversion/convert-from/convertFrom.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { E, MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI } from \"src/sd59x18/Constants.sol\";\nimport { convert } from \"src/sd59x18/Conversions.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract ConvertFrom_Unit_Test is SD59x18_Unit_Test {\n    function ltAbsoluteUnit_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: -1e18 + 1 }));\n        sets.push(set({ x: -1 }));\n        sets.push(set({ x: 0 }));\n        sets.push(set({ x: 1 }));\n        sets.push(set({ x: 1e18 - 1 }));\n        return sets;\n    }\n\n    function test_ConvertFrom_LtAbsoluteUnit() external parameterizedTest(ltAbsoluteUnit_Sets()) {\n        int256 actual = convert(s.x);\n        int256 expected = 0;\n        assertEq(actual, expected, \"SD59x18 convertFrom\");\n    }\n\n    modifier whenGteAbsoluteUnit() {\n        _;\n    }\n\n    function gteAbsoluteUnit_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, expected: MIN_SCALED_SD59x18 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, expected: MIN_SCALED_SD59x18 }));\n        sets.push(set({ x: -4.2e45, expected: -4.2e27 }));\n        sets.push(set({ x: -1729e18, expected: -0.000000000000001729e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: -0.000000000000000003e18 }));\n        sets.push(set({ x: NEGATIVE_E, expected: -0.000000000000000002e18 }));\n        sets.push(set({ x: -2e18 - 1, expected: -0.000000000000000002e18 }));\n        sets.push(set({ x: -2e18, expected: -0.000000000000000002e18 }));\n        sets.push(set({ x: -2e18 + 1, expected: -0.000000000000000001e18 }));\n        sets.push(set({ x: -1e18, expected: -0.000000000000000001e18 }));\n        sets.push(set({ x: 1e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 1e18 + 1, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 2e18 - 1, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 2e18, expected: 0.000000000000000002e18 }));\n        sets.push(set({ x: 2e18 + 1, expected: 0.000000000000000002e18 }));\n        sets.push(set({ x: E, expected: 0.000000000000000002e18 }));\n        sets.push(set({ x: PI, expected: 0.000000000000000003e18 }));\n        sets.push(set({ x: 1729e18, expected: 0.000000000000001729e18 }));\n        sets.push(set({ x: 4.2e45, expected: 4.2e27 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: MAX_SCALED_SD59x18 }));\n        sets.push(set({ x: MAX_SD59x18, expected: MAX_SCALED_SD59x18 }));\n        return sets;\n    }\n\n    function test_ConvertFrom() external parameterizedTest(gteAbsoluteUnit_Sets()) whenGteAbsoluteUnit {\n        int256 actual = convert(s.x);\n        int256 expected = s.expected.unwrap();\n        assertEq(actual, expected, \"SD59x18 convertFrom\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/conversion/convert-from/convertFrom.tree",
    "content": "convertFrom.t.sol\n├── when x is less than the absolute value of the unit number\n│  └── it should return zero\n└── when x is greater than or equal to the absolute value of the unit number\n   └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/conversion/convert-to/convertTo.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { MAX_WHOLE_SD59x18, MIN_WHOLE_SD59x18 } from \"src/sd59x18/Constants.sol\";\nimport { convert } from \"src/sd59x18/Conversions.sol\";\nimport { PRBMath_SD59x18_Convert_Overflow, PRBMath_SD59x18_Convert_Underflow } from \"src/sd59x18/Errors.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract ConvertTo_Unit_Test is SD59x18_Unit_Test {\n    function test_RevertWhen_LtMinPermitted() external {\n        int256 x = MIN_SCALED_SD59x18.unwrap() - 1;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Convert_Underflow.selector, x));\n        convert(x);\n    }\n\n    modifier whenGteMinPermitted() {\n        _;\n    }\n\n    function test_RevertWhen_GtMaxPermitted() external whenGteMinPermitted {\n        int256 x = MAX_SCALED_SD59x18.unwrap() + 1;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Convert_Overflow.selector, x));\n        convert(x);\n    }\n\n    modifier whenLteMaxPermitted() {\n        _;\n    }\n\n    function convertTo_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SCALED_SD59x18, expected: MIN_WHOLE_SD59x18 }));\n        sets.push(set({ x: -3.1415e42, expected: -3.1415e60 }));\n        sets.push(set({ x: -2.7182e38, expected: -2.7182e56 }));\n        sets.push(set({ x: -1e24, expected: -1e42 }));\n        sets.push(set({ x: -5e18, expected: -5e36 }));\n        sets.push(set({ x: -1e18, expected: -1e36 }));\n        sets.push(set({ x: -0.000000000000001729e18, expected: -1729e18 }));\n        sets.push(set({ x: -0.000000000000000002e18, expected: -2e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, expected: -1e18 }));\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e18 }));\n        sets.push(set({ x: 0.000000000000000002e18, expected: 2e18 }));\n        sets.push(set({ x: 0.000000000000001729e18, expected: 1729e18 }));\n        sets.push(set({ x: 1e18, expected: 1e36 }));\n        sets.push(set({ x: 5e18, expected: 5e36 }));\n        sets.push(set({ x: 2.7182e38, expected: 2.7182e56 }));\n        sets.push(set({ x: 3.1415e42, expected: 3.1415e60 }));\n        sets.push(set({ x: MAX_SCALED_SD59x18, expected: MAX_WHOLE_SD59x18 }));\n        return sets;\n    }\n\n    function test_ConvertTo() external parameterizedTest(convertTo_Sets()) whenGteMinPermitted whenLteMaxPermitted {\n        SD59x18 x = convert(s.x.unwrap());\n        assertEq(x, s.expected, \"SD59x18 convert to\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/conversion/convert-to/convertTo.tree",
    "content": "convertTo.t.sol\n├── when x is less than the minimum permitted\n│ └── it should revert\n└── when x is greater than or equal to the minimum permitted\n   ├── when x is greater than the maximum permitted\n   │  └── it should revert\n   └── when x is less than or equal to the maximum permitted\n      └── it should return the correct value\n\n"
  },
  {
    "path": "test/unit/sd59x18/math/abs/abs.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Abs_MinSD59x18 } from \"src/sd59x18/Errors.sol\";\nimport { abs } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Abs_Unit_Test is SD59x18_Unit_Test {\n    function test_Abs_Zero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 actual = abs(x);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 abs\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_MinSD59x18() external whenNotZero {\n        SD59x18 x = MIN_SD59x18;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Abs_MinSD59x18.selector));\n        abs(x);\n    }\n\n    modifier whenNotMinSD59x18() {\n        _;\n    }\n\n    function negative_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 + sd(1), expected: MAX_SD59x18 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, expected: MAX_WHOLE_SD59x18 }));\n        sets.push(set({ x: -1e24, expected: 1e24 }));\n        sets.push(set({ x: -4.2e18, expected: 4.2e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: PI }));\n        sets.push(set({ x: -2e18, expected: 2e18 }));\n        sets.push(set({ x: -1.125e18, expected: 1.125e18 }));\n        sets.push(set({ x: -1e18, expected: 1e18 }));\n        sets.push(set({ x: -0.5e18, expected: 0.5e18 }));\n        sets.push(set({ x: -0.1e18, expected: 0.1e18 }));\n        return sets;\n    }\n\n    function test_Abs_Negative() external parameterizedTest(negative_Sets()) whenNotZero whenNotMinSD59x18 {\n        SD59x18 actual = abs(s.x);\n        assertEq(actual, s.expected, \"SD59x18 abs\");\n    }\n\n    function positive_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: 0.1e18 }));\n        sets.push(set({ x: 0.5e18, expected: 0.5e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 1.125e18, expected: 1.125e18 }));\n        sets.push(set({ x: 2e18, expected: 2e18 }));\n        sets.push(set({ x: PI, expected: PI }));\n        sets.push(set({ x: 4.2e18, expected: 4.2e18 }));\n        sets.push(set({ x: 1e24, expected: 1e24 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: MAX_WHOLE_SD59x18 }));\n        sets.push(set({ x: MAX_SD59x18, expected: MAX_SD59x18 }));\n        return sets;\n    }\n\n    function test_Abs() external parameterizedTest(positive_Sets()) whenNotZero whenNotMinSD59x18 {\n        SD59x18 actual = abs(s.x);\n        assertEq(actual, s.expected, \"SD59x18 abs\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/abs/abs.tree",
    "content": "abs.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   ├── when x negative\n   │  ├── when x is equal to min sd59x18\n   │  │  └── it should revert\n   │  └── when x is greater than min ud60x18\n   │     └── it should return the correct value\n   └── when x is positive\n      └── it should return the correct value\n\n\n"
  },
  {
    "path": "test/unit/sd59x18/math/avg/avg.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { avg } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Avg_Unit_Test is SD59x18_Unit_Test {\n    function test_Avg_BothOperandsZero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 y = ZERO;\n        SD59x18 actual = avg(x, y);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 avg\");\n    }\n\n    function onlyOneOperandZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: -3e18, y: 0, expected: -1.5e18 }));\n        sets.push(set({ x: 0, y: -3e18, expected: -1.5e18 }));\n        sets.push(set({ x: 0, y: 3e18, expected: 1.5e18 }));\n        sets.push(set({ x: 3e18, y: 0, expected: 1.5e18 }));\n        return sets;\n    }\n\n    function test_Avg_OnlyOneOperandZero() external parameterizedTest(onlyOneOperandZero_Sets()) {\n        SD59x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 avg\");\n    }\n\n    modifier whenNeitherOperandZero() {\n        _;\n    }\n\n    function oneOperandNegativeTheOtherPositive_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, y: MAX_SD59x18, expected: 0 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, y: MAX_WHOLE_SD59x18, expected: 0 }));\n        sets.push(set({ x: -4e18, y: -2e18, expected: -3e18 }));\n        sets.push(set({ x: -2e18, y: -2e18, expected: -2e18 }));\n        sets.push(set({ x: -0.000000000000000002e18, y: 0.000000000000000004e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: 0.000000000000000003e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: 0.000000000000000002e18, expected: 0 }));\n        return sets;\n    }\n\n    function test_Avg_OneOperandNegativeTheOtherPositive()\n        external\n        parameterizedTest(oneOperandNegativeTheOtherPositive_Sets())\n        whenNeitherOperandZero\n    {\n        SD59x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 avg\");\n    }\n\n    function bothOperandsNegative_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(\n            set({\n                x: MIN_WHOLE_SD59x18,\n                y: MIN_SD59x18,\n                expected: -57896044618658097711785492504343953926634992332820282019728_396001978282409984\n            })\n        );\n        sets.push(set({ x: -4e18, y: -2e18, expected: -3e18 }));\n        sets.push(set({ x: -2e18, y: -2e18, expected: -2e18 }));\n        sets.push(set({ x: -0.000000000000000002e18, y: -0.000000000000000004e18, expected: -0.000000000000000003e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: -0.000000000000000003e18, expected: -0.000000000000000002e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: -0.000000000000000002e18, expected: -0.000000000000000001e18 }));\n        return sets;\n    }\n\n    function test_Avg_BothOperandsNegative() external parameterizedTest(bothOperandsNegative_Sets()) whenNeitherOperandZero {\n        SD59x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 avg\");\n    }\n\n    modifier whenBothOperandsPositive() {\n        _;\n    }\n\n    function bothOperandsEven_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000002e18, y: 0.000000000000000004e18, expected: 0.000000000000000003e18 }));\n        sets.push(set({ x: 2e18, y: 2e18, expected: 2e18 }));\n        sets.push(set({ x: 4e18, y: 8e18, expected: 6e18 }));\n        sets.push(set({ x: 100e18, y: 200e18, expected: 150e18 }));\n        sets.push(set({ x: 1e24, y: 1e25, expected: 5.5e24 }));\n        return sets;\n    }\n\n    function test_Avg_BothOperandsEven()\n        external\n        parameterizedTest(bothOperandsEven_Sets())\n        whenNeitherOperandZero\n        whenBothOperandsPositive\n    {\n        SD59x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 avg\");\n    }\n\n    function bothOperandsOdd_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000003e18, expected: 0.000000000000000002e18 }));\n        sets.push(set({ x: 1e18 + 1, y: 1e18 + 1, expected: 1e18 + 1 }));\n        sets.push(set({ x: 3e18 + 1, y: 7e18 + 1, expected: 5e18 + 1 }));\n        sets.push(set({ x: 99e18 + 1, y: 199e18 + 1, expected: 149e18 + 1 }));\n        sets.push(set({ x: 1e24 + 1, y: 1e25 + 1, expected: 5.5e24 + 1 }));\n        sets.push(set({ x: MAX_SD59x18, y: MAX_SD59x18, expected: MAX_SD59x18 }));\n        return sets;\n    }\n\n    function test_Avg_BothOperandsOdd() external parameterizedTest(bothOperandsOdd_Sets()) {\n        SD59x18 actual = avg(s.x, s.y);\n        logSd(s.x);\n        logSd(s.y);\n        assertEq(actual, s.expected, \"SD59x18 avg\");\n    }\n\n    function oneOperandEvenTheOtherOdd_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000002e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 1e18 + 1, y: 2e18, expected: 1.5e18 }));\n        sets.push(set({ x: 3e18 + 1, y: 8e18, expected: 5.5e18 }));\n        sets.push(set({ x: 99e18, y: 200e18, expected: 149.5e18 }));\n        sets.push(set({ x: 1e24 + 1, y: 1e25 + 1e18, expected: 5.5e24 + 0.5e18 }));\n        sets.push(\n            set({\n                x: MAX_SD59x18,\n                y: MAX_WHOLE_SD59x18,\n                expected: 57896044618658097711785492504343953926634992332820282019728_396001978282409983\n            })\n        );\n        return sets;\n    }\n\n    function test_Avg_OneOperandEvenTheOtherOdd() external parameterizedTest(oneOperandEvenTheOtherOdd_Sets()) {\n        SD59x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 avg\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/avg/avg.tree",
    "content": "avg.t.sol\n├── when both operands are zero\n│  └── it should return zero\n├── when only one operand is zero\n│  └── it should return the correct value\n└── when neither operand is zero\n   ├── when one operand is negative and the other is positive\n   │  └── it should return the correct value\n   ├── when both operands are negative\n   │  └── it should return the correct value\n   └── when both operands are positive\n      ├── when both operands are even\n      │  └── it should return the correct value\n      ├── when both operands are odd\n      │  └── it should return the correct value\n      └── when one operand is even and the other is odd\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/ceil/ceil.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Ceil_Overflow } from \"src/sd59x18/Errors.sol\";\nimport { ceil } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Ceil_Unit_Test is SD59x18_Unit_Test {\n    function test_Ceil_Zero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 actual = ceil(x);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 ceil\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function negative_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, expected: MIN_WHOLE_SD59x18 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, expected: MIN_WHOLE_SD59x18 }));\n        sets.push(set({ x: -1e24, expected: -1e24 }));\n        sets.push(set({ x: -4.2e18, expected: -4e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: -3e18 }));\n        sets.push(set({ x: -2e18, expected: -2e18 }));\n        sets.push(set({ x: -1.125e18, expected: -1e18 }));\n        sets.push(set({ x: -1e18, expected: -1e18 }));\n        sets.push(set({ x: -0.5e18, expected: 0 }));\n        sets.push(set({ x: -0.1e18, expected: 0 }));\n        return sets;\n    }\n\n    function test_Ceil_Negative() external parameterizedTest(negative_Sets()) whenNotZero {\n        SD59x18 actual = ceil(s.x);\n        assertEq(actual, s.expected, \"SD59x18 ceil\");\n    }\n\n    function test_RevertWhen_GtMaxPermitted() external whenNotZero {\n        SD59x18 x = MAX_WHOLE_SD59x18 + sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Ceil_Overflow.selector, x));\n        ceil(x);\n    }\n\n    modifier whenLteMaxPermitted() {\n        _;\n    }\n\n    function positive_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: 1e18 }));\n        sets.push(set({ x: 0.5e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 1.125e18, expected: 2e18 }));\n        sets.push(set({ x: 2e18, expected: 2e18 }));\n        sets.push(set({ x: PI, expected: 4e18 }));\n        sets.push(set({ x: 4.2e18, expected: 5e18 }));\n        sets.push(set({ x: 1e24, expected: 1e24 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: MAX_WHOLE_SD59x18 }));\n        return sets;\n    }\n\n    function test_Ceil_Positive() external parameterizedTest(positive_Sets()) whenNotZero whenLteMaxPermitted {\n        SD59x18 actual = ceil(s.x);\n        assertEq(actual, s.expected, \"SD59x18 ceil\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/ceil/ceil.tree",
    "content": "ceil.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   ├── when x negative\n   │  └── it should return the correct value\n   └── when x is positive\n      ├── when x is greater than the maximum permitted\n      │  └── it should revert\n      └── when x is less than or equal to the maximum permitted\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/div/div.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { stdError } from \"forge-std/src/StdError.sol\";\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Div_InputTooSmall, PRBMath_SD59x18_Div_Overflow } from \"src/sd59x18/Errors.sol\";\nimport { div } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Div_Unit_Test is SD59x18_Unit_Test {\n    function test_RevertWhen_DenominatorZero_Function() external {\n        SD59x18 x = sd(1e18);\n        SD59x18 y = ZERO;\n        vm.expectRevert(stdError.divisionError);\n        div(x, y);\n    }\n\n    function test_RevertWhen_DenominatorZero_Operator() external {\n        SD59x18 x = sd(1e18);\n        SD59x18 y = ZERO;\n        vm.expectRevert(stdError.divisionError);\n        x / y;\n    }\n\n    modifier whenDenominatorNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_DenominatorMinSD59x18_Function() external whenDenominatorNotZero {\n        SD59x18 x = sd(1e18);\n        SD59x18 y = MIN_SD59x18;\n        vm.expectRevert(PRBMath_SD59x18_Div_InputTooSmall.selector);\n        div(x, y);\n    }\n\n    function test_RevertWhen_DenominatorMinSD59x18_Operator() external whenDenominatorNotZero {\n        SD59x18 x = sd(1e18);\n        SD59x18 y = MIN_SD59x18;\n        vm.expectRevert(PRBMath_SD59x18_Div_InputTooSmall.selector);\n        x / y;\n    }\n\n    modifier whenDenominatorNotMinSD59x18() {\n        _;\n    }\n\n    function numeratorZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: NEGATIVE_PI, expected: 0 }));\n        sets.push(set({ x: 0, y: -1e24, expected: 0 }));\n        sets.push(set({ x: 0, y: -1e18, expected: 0 }));\n        sets.push(set({ x: 0, y: -0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0, y: 0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0, y: 1e18, expected: 0 }));\n        sets.push(set({ x: 0, y: PI, expected: 0 }));\n        sets.push(set({ x: 0, y: 1e24, expected: 0 }));\n        return sets;\n    }\n\n    function test_Div_NumeratorZero()\n        external\n        parameterizedTest(numeratorZero_Sets())\n        whenDenominatorNotZero\n        whenDenominatorNotMinSD59x18\n    {\n        assertEq(div(s.x, s.y), s.expected, \"SD59x18 div\");\n        assertEq(s.x / s.y, s.expected, \"SD59x18 /\");\n    }\n\n    modifier whenNumeratorNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_NumeratorMinSD59x18_Function()\n        external\n        whenDenominatorNotZero\n        whenDenominatorNotMinSD59x18\n        whenNumeratorNotZero\n    {\n        SD59x18 x = MIN_SD59x18;\n        SD59x18 y = sd(0.000000000000000001e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Div_InputTooSmall.selector));\n        div(x, y);\n    }\n\n    function test_RevertWhen_NumeratorMinSD59x18_Operator()\n        external\n        whenDenominatorNotZero\n        whenDenominatorNotMinSD59x18\n        whenNumeratorNotZero\n    {\n        SD59x18 x = MIN_SD59x18;\n        SD59x18 y = sd(0.000000000000000001e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Div_InputTooSmall.selector));\n        x / y;\n    }\n\n    modifier whenNumeratorNotMinSD59x18() {\n        _;\n    }\n\n    function test_RevertWhen_ResultOverflowSD59x18_Function()\n        external\n        whenDenominatorNotZero\n        whenDenominatorNotMinSD59x18\n        whenNumeratorNotZero\n        whenNumeratorNotMinSD59x18\n    {\n        SD59x18 x = MIN_SCALED_SD59x18 - sd(1);\n        SD59x18 y = sd(0.000000000000000001e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Div_Overflow.selector, x, y));\n        div(x, y);\n    }\n\n    function test_RevertWhen_ResultOverflowSD59x18_Operator()\n        external\n        whenDenominatorNotZero\n        whenDenominatorNotMinSD59x18\n        whenNumeratorNotZero\n        whenNumeratorNotMinSD59x18\n    {\n        SD59x18 x = MIN_SCALED_SD59x18 - sd(1);\n        SD59x18 y = sd(0.000000000000000001e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Div_Overflow.selector, x, y));\n        x / y;\n    }\n\n    modifier whenResultDoesNotOverflowSD59x18() {\n        _;\n    }\n\n    function numeratorDenominatorSameSign_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SCALED_SD59x18, y: -0.000000000000000001e18, expected: MAX_WHOLE_SD59x18 }));\n        sets.push(set({ x: -1e24, y: -1e18, expected: 1e24 }));\n        sets.push(set({ x: -2503e18, y: -918882.11e18, expected: 0.002723962054283546e18 }));\n        sets.push(set({ x: -772.05e18, y: -199.98e18, expected: 3_860636063606360636 }));\n        sets.push(set({ x: -100.135e18, y: -100.134e18, expected: 1_000009986617931971 }));\n        sets.push(set({ x: -22e18, y: -7e18, expected: 3_142857142857142857 }));\n        sets.push(set({ x: -4e18, y: -2e18, expected: 2e18 }));\n        sets.push(set({ x: -2e18, y: -5e18, expected: 0.4e18 }));\n        sets.push(set({ x: -2e18, y: -2e18, expected: 1e18 }));\n        sets.push(set({ x: -0.1e18, y: -0.01e18, expected: 1e19 }));\n        sets.push(set({ x: -0.05e18, y: -0.02e18, expected: 2.5e18 }));\n        sets.push(set({ x: -1e13, y: -0.00002e18, expected: 0.5e18 }));\n        sets.push(set({ x: -1e13, y: -1e13, expected: 1e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: -1e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: -1.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: MIN_SD59x18 + sd(1), expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: MAX_SD59x18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: 1.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: 1e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 1e13, y: 1e13, expected: 1e18 }));\n        sets.push(set({ x: 1e13, y: 0.00002e18, expected: 0.5e18 }));\n        sets.push(set({ x: 0.05e18, y: 0.02e18, expected: 2.5e18 }));\n        sets.push(set({ x: 0.1e18, y: 0.01e18, expected: 10e18 }));\n        sets.push(set({ x: 2e18, y: 2e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, y: 5e18, expected: 0.4e18 }));\n        sets.push(set({ x: 4e18, y: 2e18, expected: 2e18 }));\n        sets.push(set({ x: 22e18, y: 7e18, expected: 3_142857142857142857 }));\n        sets.push(set({ x: 100.135e18, y: 100.134e18, expected: 1_000009986617931971 }));\n        sets.push(set({ x: 772.05e18, y: 199.98e18, expected: 3_860636063606360636 }));\n        sets.push(set({ x: 2503e18, y: 918882.11e18, expected: 0.002723962054283546e18 }));\n        sets.push(set({ x: 1e24, y: 1e18, expected: 1e24 }));\n        sets.push(set({ x: MAX_SCALED_SD59x18, y: 0.000000000000000001e18, expected: MAX_WHOLE_SD59x18 }));\n        return sets;\n    }\n\n    function test_Div_NumeratorDenominatorSameSign()\n        external\n        parameterizedTest(numeratorDenominatorSameSign_Sets())\n        whenDenominatorNotZero\n        whenDenominatorNotMinSD59x18\n        whenNumeratorNotZero\n        whenNumeratorNotMinSD59x18\n        whenResultDoesNotOverflowSD59x18\n    {\n        assertEq(div(s.x, s.y), s.expected, \"SD59x18 div\");\n        assertEq(s.x / s.y, s.expected, \"SD59x18 /\");\n    }\n\n    function numeratorDenominatorDifferentSign_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SCALED_SD59x18, y: 0.000000000000000001e18, expected: MIN_WHOLE_SD59x18 }));\n        sets.push(set({ x: -1e24, y: 1e18, expected: -1e24 }));\n        sets.push(set({ x: -2503e18, y: 918882.11e18, expected: -0.002723962054283546e18 }));\n        sets.push(set({ x: -772.05e18, y: 199.98e18, expected: -3_860636063606360636 }));\n        sets.push(set({ x: -100.135e18, y: 100.134e18, expected: -1_000009986617931971 }));\n        sets.push(set({ x: -22e18, y: 7e18, expected: -3_142857142857142857 }));\n        sets.push(set({ x: -4e18, y: 2e18, expected: -2e18 }));\n        sets.push(set({ x: -2e18, y: 5e18, expected: -0.4e18 }));\n        sets.push(set({ x: -2e18, y: 2e18, expected: -1e18 }));\n        sets.push(set({ x: -0.1e18, y: 0.01e18, expected: -1e19 }));\n        sets.push(set({ x: -0.05e18, y: 0.02e18, expected: -2.5e18 }));\n        sets.push(set({ x: -1e13, y: 2e13, expected: -0.5e18 }));\n        sets.push(set({ x: -1e13, y: 1e13, expected: -1e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: 1e18, expected: -0.000000000000000001e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: 1.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: MAX_SD59x18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: MIN_SD59x18 + sd(1), expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: -1.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: -1e18, expected: -0.000000000000000001e18 }));\n        sets.push(set({ x: 1e13, y: -1e13, expected: -1e18 }));\n        sets.push(set({ x: 1e13, y: -2e13, expected: -0.5e18 }));\n        sets.push(set({ x: 0.05e18, y: -0.02e18, expected: -2.5e18 }));\n        sets.push(set({ x: 0.1e18, y: -0.01e18, expected: -10e18 }));\n        sets.push(set({ x: 2e18, y: -2e18, expected: -1e18 }));\n        sets.push(set({ x: 2e18, y: -5e18, expected: -0.4e18 }));\n        sets.push(set({ x: 4e18, y: -2e18, expected: -2e18 }));\n        sets.push(set({ x: 22e18, y: -7e18, expected: -3_142857142857142857 }));\n        sets.push(set({ x: 100.135e18, y: -100.134e18, expected: -1_000009986617931971 }));\n        sets.push(set({ x: 772.05e18, y: -199.98e18, expected: -3_860636063606360636 }));\n        sets.push(set({ x: 2503e18, y: -918882.11e18, expected: -0.002723962054283546e18 }));\n        sets.push(set({ x: 1e24, y: -1e18, expected: -1e24 }));\n        sets.push(set({ x: MAX_SCALED_SD59x18, y: 0.000000000000000001e18, expected: MAX_WHOLE_SD59x18 }));\n        return sets;\n    }\n\n    function test_Div_NumeratorDenominatorDifferentSign()\n        external\n        parameterizedTest(numeratorDenominatorDifferentSign_Sets())\n        whenDenominatorNotZero\n        whenDenominatorNotMinSD59x18\n        whenNumeratorNotZero\n        whenNumeratorNotMinSD59x18\n        whenResultDoesNotOverflowSD59x18\n    {\n        assertEq(div(s.x, s.y), s.expected, \"SD59x18 div\");\n        assertEq(s.x / s.y, s.expected, \"SD59x18 /\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/div/div.tree",
    "content": "div.t.sol\n├── when the denominator is zero\n│  └── it should revert\n└── when the denominator is not zero\n   ├── when the denominator is min sd59x18\n   │  └── it should revert\n   └── when the denominator is not min sd59x18\n      ├── when the numerator is zero\n      │  └── it should return zero\n      └── when the numerator is not zero\n        ├── when the numerator is min sd59x18\n        │  └── it should revert\n        └── when the numerator is not min sd59x18\n           ├── when the result overflows sd59x18\n           │  └── it should revert\n           └── when the result does not overflow sd59x18\n              ├── when the numerator and the denominator have the same sign\n              │  └── it should return the correct value\n              └── when the numerator and the denominator have different signs\n                 └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/exp/exp.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, EXP_MAX_INPUT, EXP_MIN_THRESHOLD, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, UNIT, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Exp_InputTooBig } from \"src/sd59x18/Errors.sol\";\nimport { exp } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Exp_Unit_Test is SD59x18_Unit_Test {\n    function test_Exp_Zero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 actual = exp(x);\n        SD59x18 expected = UNIT;\n        assertEq(actual, expected, \"SD59x18 exp\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function ltThreshold_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18 }));\n        sets.push(set({ x: EXP_MIN_THRESHOLD - sd(1) }));\n        return sets;\n    }\n\n    function test_Exp_Negative_LtThreshold() external parameterizedTest(ltThreshold_Sets()) whenNotZero {\n        SD59x18 actual = exp(s.x);\n        assertEq(actual, s.expected, \"SD59x18 exp\");\n    }\n\n    function negativeAndGteThreshold_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, expected: 0 }));\n        sets.push(set({ x: EXP_MIN_THRESHOLD - sd(1), expected: 0 }));\n        sets.push(set({ x: EXP_MIN_THRESHOLD, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: -33.333333e18, expected: 0.000000000000003338e18 }));\n        sets.push(set({ x: -20.82e18, expected: 0.0000000009077973e18 }));\n        sets.push(set({ x: -16e18, expected: 0.000000112535174719e18 }));\n        sets.push(set({ x: -11.89215e18, expected: 0.000006843919254514e18 }));\n        sets.push(set({ x: -4e18, expected: 0.01831563888873418e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: 0.043213918263772249e18 }));\n        sets.push(set({ x: -3e18, expected: 0.049787068367863943e18 }));\n        sets.push(set({ x: NEGATIVE_E, expected: 0.065988035845312537e18 }));\n        sets.push(set({ x: -2e18, expected: 0.135335283236612691e18 }));\n        sets.push(set({ x: -1e18, expected: 0.367879441171442321e18 }));\n        sets.push(set({ x: -1e3, expected: 0.999999999999999001e18 }));\n        sets.push(set({ x: -1, expected: 1e18 }));\n        return sets;\n    }\n\n    function test_Exp_Negative_GteMinPermitted() external parameterizedTest(negativeAndGteThreshold_Sets()) whenNotZero {\n        SD59x18 actual = exp(s.x);\n        assertEq(actual, s.expected, \"SD59x18 exp\");\n    }\n\n    function test_RevertWhen_Positive_GtMaxPermitted() external whenNotZero {\n        SD59x18 x = EXP_MAX_INPUT + sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Exp_InputTooBig.selector, x));\n        exp(x);\n    }\n\n    function positiveAndLteMaxPermitted_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e18 }));\n        sets.push(set({ x: 0.000000000000001e18, expected: 1.000000000000000999e18 }));\n        sets.push(set({ x: 1e18, expected: 2_718281828459045234 }));\n        sets.push(set({ x: 2e18, expected: 7_389056098930650223 }));\n        sets.push(set({ x: E, expected: 15_154262241479264171 }));\n        sets.push(set({ x: 3e18, expected: 20_085536923187667724 }));\n        sets.push(set({ x: PI, expected: 23_140692632779268962 }));\n        sets.push(set({ x: 4e18, expected: 54_598150033144239019 }));\n        sets.push(set({ x: 11.89215e18, expected: 146115_107851442195738190 }));\n        sets.push(set({ x: 16e18, expected: 8886110_520507872601090007 }));\n        sets.push(set({ x: 20.82e18, expected: 1101567497_354306722521735975 }));\n        sets.push(set({ x: 33.333333e18, expected: 299559147061116_199277615819889397 }));\n        sets.push(set({ x: 64e18, expected: 6235149080811616783682415370_612321304359995711 }));\n        sets.push(set({ x: 71.002e18, expected: 6851360256686183998595702657852_843771046889809565 }));\n        sets.push(set({ x: 88.722839111672999627e18, expected: 340282366920938463222979506443879150094_819893272894857679 }));\n        sets.push(set({ x: EXP_MAX_INPUT, expected: 6277101735386680754977611748738314679353920434623901771623e18 }));\n        return sets;\n    }\n\n    function test_Exp_Positive_LteMaxPermitted() external parameterizedTest(positiveAndLteMaxPermitted_Sets()) whenNotZero {\n        SD59x18 actual = exp(s.x);\n        assertEq(actual, s.expected, \"SD59x18 exp\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/exp/exp.tree",
    "content": "exp.t.sol\n├── when x is zero\n│  └── it should return the unit number\n└── when x is not zero\n   ├── when x is negative\n   │  ├── when x is less than a particular threshold\n   │  │  └── it should return zero\n   │  └── when x is greater than or equal to a particular threshold\n   │     └── it should return the correct value\n   └── when x is positive\n      ├── when x is greater than the maximum permitted\n      │  └── it should revert\n      └── when x is less than or equal to the maximum permitted\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/exp2/exp2.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, EXP2_MAX_INPUT, EXP2_MIN_THRESHOLD, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, UNIT, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Exp2_InputTooBig } from \"src/sd59x18/Errors.sol\";\nimport { exp2 } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Exp2_Unit_Test is SD59x18_Unit_Test {\n    function test_Exp2_Zero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 actual = exp2(x);\n        SD59x18 expected = UNIT;\n        assertEq(actual, expected, \"SD59x18 exp2\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function negativeAndLtThreshold_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, expected: 0 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, expected: 0 }));\n        sets.push(set({ x: EXP2_MIN_THRESHOLD - sd(1), expected: 0 }));\n        return sets;\n    }\n\n    function test_Exp2_Negative_LtThreshold() external parameterizedTest(negativeAndLtThreshold_Sets()) whenNotZero {\n        SD59x18 actual = exp2(s.x);\n        assertEq(actual, s.expected, \"SD59x18 exp2\");\n    }\n\n    function negativeAndGteMinPermitted_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, expected: 0 }));\n        sets.push(set({ x: EXP2_MIN_THRESHOLD - sd(1), expected: 0 }));\n        sets.push(set({ x: EXP2_MIN_THRESHOLD, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: -33.333333e18, expected: 0.000000000092398923e18 }));\n        sets.push(set({ x: -20.82e18, expected: 0.000000540201132438e18 }));\n        sets.push(set({ x: -16e18, expected: 0.0000152587890625e18 }));\n        sets.push(set({ x: -11.89215e18, expected: 0.000263091088065207e18 }));\n        sets.push(set({ x: -4e18, expected: 0.0625e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: 0.113314732296760873e18 }));\n        sets.push(set({ x: -3e18, expected: 0.125e18 }));\n        sets.push(set({ x: NEGATIVE_E, expected: 0.151955223257912965e18 }));\n        sets.push(set({ x: -2e18, expected: 0.25e18 }));\n        sets.push(set({ x: -1e18, expected: 0.5e18 }));\n        sets.push(set({ x: -0.000000000000001e18, expected: 0.999999999999999307e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, expected: 1e18 }));\n        return sets;\n    }\n\n    function test_Exp2_Negative_GteMinPermitted() external parameterizedTest(negativeAndGteMinPermitted_Sets()) whenNotZero {\n        SD59x18 actual = exp2(s.x);\n        assertEq(actual, s.expected, \"SD59x18 exp2\");\n    }\n\n    function test_RevertWhen_Positive_GtMaxPermitted() external whenNotZero {\n        SD59x18 x = EXP2_MAX_INPUT + sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Exp2_InputTooBig.selector, x));\n        exp2(x);\n    }\n\n    modifier whenLtMaxPermitted() {\n        _;\n    }\n\n    function positiveAndLTePermitted_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e18 }));\n        sets.push(set({ x: 1e3, expected: 1_000000000000000693 }));\n        sets.push(set({ x: 0.3212e18, expected: 1_249369313012024883 }));\n        sets.push(set({ x: 1e18, expected: 2e18 }));\n        sets.push(set({ x: 2e18, expected: 4e18 }));\n        sets.push(set({ x: E, expected: 6_580885991017920969 }));\n        sets.push(set({ x: 3e18, expected: 8e18 }));\n        sets.push(set({ x: PI, expected: 8_824977827076287621 }));\n        sets.push(set({ x: 4e18, expected: 16e18 }));\n        sets.push(set({ x: 11.89215e18, expected: 3800_964933301542754377 }));\n        sets.push(set({ x: 16e18, expected: 65536e18 }));\n        sets.push(set({ x: 20.82e18, expected: 1851162_354076939434682641 }));\n        sets.push(set({ x: 33.333333e18, expected: 10822636909_120553492168423503 }));\n        sets.push(set({ x: 64e18, expected: 18_446744073709551616e18 }));\n        sets.push(set({ x: 71.002e18, expected: 2364458806372010440881_644926416580874919 }));\n        sets.push(set({ x: 88.7494e18, expected: 520273250104929479163928177_984511174562086061 }));\n        sets.push(set({ x: 95e18, expected: 39614081257_132168796771975168e18 }));\n        sets.push(set({ x: 127e18, expected: 170141183460469231731_687303715884105728e18 }));\n        sets.push(set({ x: 152.9065e18, expected: 10701459987152828635116598811554803403437267307_663014047009710338 }));\n        sets.push(set({ x: EXP2_MAX_INPUT, expected: 6277101735386680759401282518710514696272033118492751795945e18 }));\n        return sets;\n    }\n\n    function test_Exp2_Positive_LTePermittedMax() external parameterizedTest(positiveAndLTePermitted_Sets()) whenNotZero {\n        SD59x18 actual = exp2(s.x);\n        assertEq(actual, s.expected, \"SD59x18 exp2\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/exp2/exp2.tree",
    "content": "exp2.t.sol\n├── when x is zero\n│  └── it should return the unit number\n└── when x is not zero\n   ├── when x is negative\n   │  ├── when x is less than a particular threshold\n   │  │  └── it should return zero\n   │  └── when x is greater than or equal to a particular threshold\n   │     └── it should return the correct value\n   └── when x is positive\n      ├── when x is greater than the maximum permitted\n      │  └── it should revert\n      └── when x is less than the maximum permitted\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/floor/floor.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Floor_Underflow } from \"src/sd59x18/Errors.sol\";\nimport { floor } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Floor_Unit_Test is SD59x18_Unit_Test {\n    function test_Floor_Zero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 actual = floor(x);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 floor\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_Negative_LtMinPermitted() external whenNotZero {\n        SD59x18 x = MIN_WHOLE_SD59x18 - sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Floor_Underflow.selector, x));\n        floor(x);\n    }\n\n    function negativeAndGteMinPermitted_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_WHOLE_SD59x18, expected: MIN_WHOLE_SD59x18 }));\n        sets.push(set({ x: -1e24, expected: -1e24 }));\n        sets.push(set({ x: -4.2e18, expected: -5e18 }));\n        sets.push(set({ x: -2e18, expected: -2e18 }));\n        sets.push(set({ x: -1.125e18, expected: -2e18 }));\n        sets.push(set({ x: -1e18, expected: -1e18 }));\n        sets.push(set({ x: -0.5e18, expected: -1e18 }));\n        sets.push(set({ x: -0.1e18, expected: -1e18 }));\n        return sets;\n    }\n\n    function test_Floor_Negative_GteMinPermitted() external parameterizedTest(negativeAndGteMinPermitted_Sets()) whenNotZero {\n        SD59x18 actual = floor(s.x);\n        assertEq(actual, s.expected, \"SD59x18 floor\");\n    }\n\n    function positive_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: 0 }));\n        sets.push(set({ x: 0.5e18, expected: 0 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 1.125e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, expected: 2e18 }));\n        sets.push(set({ x: PI, expected: 3e18 }));\n        sets.push(set({ x: 4.2e18, expected: 4e18 }));\n        sets.push(set({ x: 1e24, expected: 1e24 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: MAX_WHOLE_SD59x18 }));\n        sets.push(set({ x: MAX_SD59x18, expected: MAX_WHOLE_SD59x18 }));\n        return sets;\n    }\n\n    function test_Floor_Positive() external parameterizedTest(positive_Sets()) whenNotZero {\n        SD59x18 actual = floor(s.x);\n        assertEq(actual, s.expected, \"SD59x18 floor\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/floor/floor.tree",
    "content": "floor.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   ├── when x is negative\n   │  ├── when x is less than the minimum permitted\n   │  │  └── it should revert\n   │  └── when x is greater than or equal to the minimum permitted\n   │     └── it should return the correct value\n   └── when x is positive\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/frac/frac.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { frac } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Frac_Unit_Test is SD59x18_Unit_Test {\n    function test_Frac_Zero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 actual = frac(x);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 frac\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function negative_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, expected: -0.792003956564819968e18 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, expected: 0 }));\n        sets.push(set({ x: -1e24, expected: 0 }));\n        sets.push(set({ x: -4.2e18, expected: -0.2e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: -0.141592653589793238e18 }));\n        sets.push(set({ x: -2e18, expected: 0 }));\n        sets.push(set({ x: -1.125e18, expected: -0.125e18 }));\n        sets.push(set({ x: -1e18, expected: 0 }));\n        sets.push(set({ x: -0.5e18, expected: -0.5e18 }));\n        sets.push(set({ x: -0.1e18, expected: -0.1e18 }));\n        return sets;\n    }\n\n    function test_Frac_Negative() external parameterizedTest(negative_Sets()) whenNotZero {\n        SD59x18 actual = frac(s.x);\n        assertEq(actual, s.expected, \"SD59x18 frac\");\n    }\n\n    function positive_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: 0.1e18 }));\n        sets.push(set({ x: 0.5e18, expected: 0.5e18 }));\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 1.125e18, expected: 0.125e18 }));\n        sets.push(set({ x: 2e18, expected: 0 }));\n        sets.push(set({ x: PI, expected: 0.141592653589793238e18 }));\n        sets.push(set({ x: 4.2e18, expected: 0.2e18 }));\n        sets.push(set({ x: 1e24, expected: 0 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: 0 }));\n        sets.push(set({ x: MAX_SD59x18, expected: 0.792003956564819967e18 }));\n        return sets;\n    }\n\n    function test_Frac() external parameterizedTest(positive_Sets()) whenNotZero {\n        SD59x18 actual = frac(s.x);\n        assertEq(actual, s.expected, \"SD59x18 frac\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/frac/frac.tree",
    "content": "frac.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   ├── when x is negative\n   │  └── it should return the correct value\n   └── when x is positive\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/gm/gm.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Gm_Overflow, PRBMath_SD59x18_Gm_NegativeProduct } from \"src/sd59x18/Errors.sol\";\nimport { gm } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Gm_Unit_Test is SD59x18_Unit_Test {\n    /// @dev Greatest number whose non-fixed-point square fits within int256\n    SD59x18 internal constant SQRT_MAX_INT256 = SD59x18.wrap(240615969168004511545_033772477625056927);\n    /// @dev Smallest number whose non-fixed-point square fits within int256\n    SD59x18 internal constant NEGATIVE_SQRT_MAX_INT256 = SD59x18.wrap(-240615969168004511545033772477625056927);\n\n    function oneOperandZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: PI, expected: 0 }));\n        sets.push(set({ x: PI, y: 0, expected: 0 }));\n        return sets;\n    }\n\n    function test_Gm_OneOperandZero() external parameterizedTest(oneOperandZero_Sets()) {\n        SD59x18 actual = gm(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 gm\");\n    }\n\n    modifier whenOperandsNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_ProductNegative_A() external whenOperandsNotZero {\n        SD59x18 x = sd(-1e18);\n        SD59x18 y = PI;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Gm_NegativeProduct.selector, x, y));\n        gm(x, y);\n    }\n\n    function test_RevertWhen_ProductNegative_B() external whenOperandsNotZero {\n        SD59x18 x = PI;\n        SD59x18 y = sd(-1e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Gm_NegativeProduct.selector, x, y));\n        gm(x, y);\n    }\n\n    modifier whenProductPositive() {\n        _;\n    }\n\n    function test_RevertWhen_ProductOverflow_A() external whenOperandsNotZero whenProductPositive {\n        SD59x18 x = MIN_SD59x18;\n        SD59x18 y = sd(0.000000000000000002e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Gm_Overflow.selector, x, y));\n        gm(x, y);\n    }\n\n    function test_RevertWhen_ProductOverflow_B() external whenOperandsNotZero whenProductPositive {\n        SD59x18 x = NEGATIVE_SQRT_MAX_INT256;\n        SD59x18 y = NEGATIVE_SQRT_MAX_INT256 - sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Gm_Overflow.selector, x, y));\n        gm(x, y);\n    }\n\n    function test_RevertWhen_ProductOverflow_C() external whenOperandsNotZero whenProductPositive {\n        SD59x18 x = SQRT_MAX_INT256 + sd(1);\n        SD59x18 y = SQRT_MAX_INT256 + sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Gm_Overflow.selector, x, y));\n        gm(x, y);\n    }\n\n    function test_RevertWhen_ProductOverflow_D() external whenOperandsNotZero whenProductPositive {\n        SD59x18 x = MAX_SD59x18;\n        SD59x18 y = sd(0.000000000000000002e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Gm_Overflow.selector, x, y));\n        gm(x, y);\n    }\n\n    modifier whenProductDoesNotOverflow() {\n        _;\n    }\n\n    function gm_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_WHOLE_SD59x18, y: -0.000000000000000001e18, expected: SQRT_MAX_INT256 }));\n        sets.push(set({ x: NEGATIVE_SQRT_MAX_INT256, y: NEGATIVE_SQRT_MAX_INT256, expected: SQRT_MAX_INT256 }));\n        sets.push(set({ x: -2404.8e18, y: -7899.210662e18, expected: 4358_442588812843362311 }));\n        sets.push(set({ x: -322.47e18, y: -674.77e18, expected: 466_468736251423392217 }));\n        sets.push(set({ x: NEGATIVE_PI, y: -8.2e18, expected: 5_075535416036056441 }));\n        sets.push(set({ x: NEGATIVE_E, y: -89.01e18, expected: 15_554879155787087514 }));\n        sets.push(set({ x: -2e18, y: -8e18, expected: 4e18 }));\n        sets.push(set({ x: -1e18, y: -4e18, expected: 2e18 }));\n        sets.push(set({ x: -1e18, y: -1e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, y: 4e18, expected: 2e18 }));\n        sets.push(set({ x: 2e18, y: 8e18, expected: 4e18 }));\n        sets.push(set({ x: E, y: 89.01e18, expected: 15_554879155787087514 }));\n        sets.push(set({ x: PI, y: 8.2e18, expected: 5_075535416036056441 }));\n        sets.push(set({ x: 322.47e18, y: 674.77e18, expected: 466_468736251423392217 }));\n        sets.push(set({ x: 2404.8e18, y: 7899.210662e18, expected: 4358_442588812843362311 }));\n        sets.push(set({ x: SQRT_MAX_INT256, y: SQRT_MAX_INT256, expected: SQRT_MAX_INT256 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, y: 0.000000000000000001e18, expected: SQRT_MAX_INT256 }));\n        sets.push(set({ x: MAX_SD59x18, y: 0.000000000000000001e18, expected: SQRT_MAX_INT256 }));\n        return sets;\n    }\n\n    function test_Gm() external parameterizedTest(gm_Sets()) whenOperandsNotZero whenProductPositive whenProductDoesNotOverflow {\n        SD59x18 actual = gm(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 gm\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/gm/gm.tree",
    "content": "gm.t.sol\n├── when one of the operands is zero\n│  └── it should return zero\n└── when neither operand is zero\n   ├── when the product of x and y is negative\n   │  └── it should revert\n   └── when the product of x and y is positive\n     ├── when the product of x and y overflows\n     │  └── it should revert\n     └── when the product of x and y does not overflow\n        └── it should return the correct value\n\n"
  },
  {
    "path": "test/unit/sd59x18/math/inv/inv.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { stdError } from \"forge-std/src/StdError.sol\";\n\nimport { MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { inv } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Inv_Unit_Test is SD59x18_Unit_Test {\n    function test_RevertWhen_Zero() external {\n        SD59x18 x = ZERO;\n        vm.expectRevert(stdError.divisionError);\n        inv(x);\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function negative_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18, expected: 0 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, expected: 0 }));\n        sets.push(set({ x: -1e36 - 1, expected: 0 }));\n        sets.push(set({ x: -1e36, expected: -1 }));\n        sets.push(set({ x: -2503e18, expected: -0.000399520575309628e18 }));\n        sets.push(set({ x: -772.05e18, expected: -0.001295252898128359e18 }));\n        sets.push(set({ x: -100.135e18, expected: -0.00998651820042942e18 }));\n        sets.push(set({ x: -22e18, expected: -0.045454545454545454e18 }));\n        sets.push(set({ x: -4e18, expected: -0.25e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: -0.318309886183790671e18 }));\n        sets.push(set({ x: -2e18, expected: -0.5e18 }));\n        sets.push(set({ x: -1e18, expected: -1e18 }));\n        sets.push(set({ x: -0.1e18, expected: -10e18 }));\n        sets.push(set({ x: -0.05e18, expected: -20e18 }));\n        sets.push(set({ x: -0.00001e18, expected: -100_000e18 }));\n        sets.push(set({ x: -1, expected: -1e36 }));\n        return sets;\n    }\n\n    function test_Inv_Negative() external parameterizedTest(negative_Sets()) whenNotZero {\n        SD59x18 actual = inv(s.x);\n        assertEq(actual, s.expected, \"SD59x18 inv\");\n    }\n\n    function positive_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e36 }));\n        sets.push(set({ x: 0.00001e18, expected: 100_000e18 }));\n        sets.push(set({ x: 0.05e18, expected: 20e18 }));\n        sets.push(set({ x: 0.1e18, expected: 10e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, expected: 0.5e18 }));\n        sets.push(set({ x: PI, expected: 0.318309886183790671e18 }));\n        sets.push(set({ x: 4e18, expected: 0.25e18 }));\n        sets.push(set({ x: 22e18, expected: 0.045454545454545454e18 }));\n        sets.push(set({ x: 100.135e18, expected: 0.00998651820042942e18 }));\n        sets.push(set({ x: 772.05e18, expected: 0.001295252898128359e18 }));\n        sets.push(set({ x: 2503e18, expected: 0.000399520575309628e18 }));\n        sets.push(set({ x: 1e36, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 1e36 + 1, expected: 0 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: 0 }));\n        sets.push(set({ x: MAX_SD59x18, expected: 0 }));\n        return sets;\n    }\n\n    function test_Inv_Positive() external parameterizedTest(positive_Sets()) whenNotZero {\n        SD59x18 actual = inv(s.x);\n        assertEq(actual, s.expected, \"SD59x18 inv\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/inv/inv.tree",
    "content": "inv.t.sol\n├── when x is zero\n│  └── it should revert\n└── when x is not zero\n   ├── when x is negative\n   │  └── it should return the correct value\n   └── when x is positive\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/ln/ln.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, MAX_SD59x18, MAX_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Log_InputTooSmall } from \"src/sd59x18/Errors.sol\";\nimport { ln } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Ln_Unit_Test is SD59x18_Unit_Test {\n    function test_RevertWhen_Zero() external {\n        SD59x18 x = ZERO;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Log_InputTooSmall.selector, x));\n        ln(x);\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_Negative() external whenNotZero {\n        SD59x18 x = sd(-1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Log_InputTooSmall.selector, x));\n        ln(x);\n    }\n\n    modifier whenPositive() {\n        _;\n    }\n\n    function ln_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: -2_302585092994045674 }));\n        sets.push(set({ x: 0.2e18, expected: -1_609437912434100365 }));\n        sets.push(set({ x: 0.3e18, expected: -1_203972804325935984 }));\n        sets.push(set({ x: 0.4e18, expected: -0.916290731874155055e18 }));\n        sets.push(set({ x: 0.5e18, expected: -0.693147180559945309e18 }));\n        sets.push(set({ x: 0.6e18, expected: -0.510825623765990674e18 }));\n        sets.push(set({ x: 0.7e18, expected: -0.356674943938732371e18 }));\n        sets.push(set({ x: 0.8e18, expected: -0.223143551314209746e18 }));\n        sets.push(set({ x: 0.9e18, expected: -0.105360515657826292e18 }));\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 1.125e18, expected: 0.117783035656383442e18 }));\n        sets.push(set({ x: 2e18, expected: 0.693147180559945309e18 }));\n        sets.push(set({ x: E, expected: 0.99999999999999999e18 }));\n        sets.push(set({ x: PI, expected: 1_144729885849400163 }));\n        sets.push(set({ x: 4e18, expected: 1_386294361119890619 }));\n        sets.push(set({ x: 8e18, expected: 2_079441541679835928 }));\n        sets.push(set({ x: 1e24, expected: 13_815510557964274099 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: 135_305999368893231615 }));\n        sets.push(set({ x: MAX_SD59x18, expected: 135_305999368893231615 }));\n        return sets;\n    }\n\n    function test_Ln() external parameterizedTest(ln_Sets()) whenNotZero whenPositive {\n        SD59x18 actual = ln(s.x);\n        assertEq(actual, s.expected, \"SD59x18 ln\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/ln/ln.tree",
    "content": "ln.t.sol\n├── when x is zero\n│  └── it should revert\n└── when x is not zero\n   ├── when x is negative\n   │  └── it should revert\n   └── when x is positive\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/log10/log10.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, MAX_SD59x18, MAX_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Log_InputTooSmall } from \"src/sd59x18/Errors.sol\";\nimport { log10 } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Log10_Unit_Test is SD59x18_Unit_Test {\n    function test_RevertWhen_Zero() external {\n        SD59x18 x = ZERO;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Log_InputTooSmall.selector, x));\n        log10(x);\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_Negative() external whenNotZero {\n        SD59x18 x = sd(-1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Log_InputTooSmall.selector, x));\n        log10(x);\n    }\n\n    modifier whenPositive() {\n        _;\n    }\n\n    function powerOfTen_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: -18e18 }));\n        sets.push(set({ x: 0.00000000000000001e18, expected: -17e18 }));\n        sets.push(set({ x: 0.00000000000001e18, expected: -14e18 }));\n        sets.push(set({ x: 0.0000000001e18, expected: -10e18 }));\n        sets.push(set({ x: 0.00000001e18, expected: -8e18 }));\n        sets.push(set({ x: 0.0000001e18, expected: -7e18 }));\n        sets.push(set({ x: 0.001e18, expected: -3e18 }));\n        sets.push(set({ x: 0.1e18, expected: -1e18 }));\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 10e18, expected: 1e18 }));\n        sets.push(set({ x: 100e18, expected: 2e18 }));\n        sets.push(set({ x: 1e24, expected: 6e18 }));\n        sets.push(set({ x: 1e67, expected: 49e18 }));\n        sets.push(set({ x: 1e75, expected: 57e18 }));\n        sets.push(set({ x: 1e76, expected: 58e18 }));\n        return sets;\n    }\n\n    function test_Log10_PowerOfTen() external parameterizedTest(powerOfTen_Sets()) whenNotZero whenPositive {\n        SD59x18 actual = log10(s.x);\n        assertEq(actual, s.expected, \"SD59x18 log10\");\n    }\n\n    function notPowerOfTen_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 7.892191e6, expected: -11_102802412872166458 }));\n        sets.push(set({ x: 0.0091e18, expected: -2_040958607678906397 }));\n        sets.push(set({ x: 0.083e18, expected: -1_080921907623926093 }));\n        sets.push(set({ x: 0.1982e18, expected: -702896349850743472 }));\n        sets.push(set({ x: 0.313e18, expected: -504455662453551511 }));\n        sets.push(set({ x: 0.4666e18, expected: -331055265542266175 }));\n        sets.push(set({ x: 1.00000000000001e18, expected: 0.000000000000004341e18 }));\n        sets.push(set({ x: E, expected: 0.434294481903251823e18 }));\n        sets.push(set({ x: PI, expected: 0.497149872694133849e18 }));\n        sets.push(set({ x: 4e18, expected: 0.60205999132796239e18 }));\n        sets.push(set({ x: 16e18, expected: 1_204119982655924781 }));\n        sets.push(set({ x: 32e18, expected: 1_505149978319905976 }));\n        sets.push(set({ x: 42.12e18, expected: 1_624488362513448905 }));\n        sets.push(set({ x: 1010.892143e18, expected: 3_004704821071980110 }));\n        sets.push(set({ x: 440934.1881e18, expected: 5_644373773418177966 }));\n        sets.push(set({ x: 1000000000000000000.000000000001e18, expected: 17_999999999999999999 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: 58_762648894315204791 }));\n        sets.push(set({ x: MAX_SD59x18, expected: 58_762648894315204791 }));\n        return sets;\n    }\n\n    function test_Log10_NotPowerOfTen() external parameterizedTest(notPowerOfTen_Sets()) whenNotZero whenPositive {\n        SD59x18 actual = log10(s.x);\n        assertEq(actual, s.expected, \"SD59x18 log10\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/log10/log10.tree",
    "content": "log10.t.sol\n├── when x is zero\n│  └── it should revert\n└── when x is not zero\n   ├── when x is negative\n   │  └── it should revert\n   └── when x is positive\n      ├── when x is a power of ten\n      │  └── it should return the correct value\n      └── when x is not a power of ten\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/log2/log2.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, MAX_SD59x18, MAX_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Log_InputTooSmall } from \"src/sd59x18/Errors.sol\";\nimport { log2 } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Log2_Unit_Test is SD59x18_Unit_Test {\n    function test_RevertWhen_Zero() external {\n        SD59x18 x = ZERO;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Log_InputTooSmall.selector, x));\n        log2(x);\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_Negative() external whenNotZero {\n        SD59x18 x = sd(-1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Log_InputTooSmall.selector, x));\n        log2(x);\n    }\n\n    modifier whenPositive() {\n        _;\n    }\n\n    function powerOfTwo_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.0625e18, expected: -4e18 }));\n        sets.push(set({ x: 0.125e18, expected: -3e18 }));\n        sets.push(set({ x: 0.25e18, expected: -2e18 }));\n        sets.push(set({ x: 0.5e18, expected: -1e18 }));\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 2e18, expected: 1e18 }));\n        sets.push(set({ x: 4e18, expected: 2e18 }));\n        sets.push(set({ x: 8e18, expected: 3e18 }));\n        sets.push(set({ x: 16e18, expected: 4e18 }));\n        sets.push(set({ x: 2 ** 195 * 1e18, expected: 195e18 }));\n        return sets;\n    }\n\n    function test_Log2_PowerOfTwo() external parameterizedTest(powerOfTwo_Sets()) whenNotZero whenPositive {\n        SD59x18 actual = log2(s.x);\n        assertEq(actual, s.expected, \"SD59x18 log2\");\n    }\n\n    function notPowerOfTwo_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.0091e18, expected: -6_779917739350753112 }));\n        sets.push(set({ x: 0.083e18, expected: -3_590744853315162277 }));\n        sets.push(set({ x: 0.1e18, expected: -3_321928094887362334 }));\n        sets.push(set({ x: 0.2e18, expected: -2_321928094887362334 }));\n        sets.push(set({ x: 0.3e18, expected: -1_736965594166206154 }));\n        sets.push(set({ x: 0.4e18, expected: -1_321928094887362334 }));\n        sets.push(set({ x: 0.6e18, expected: -0.736965594166206154e18 }));\n        sets.push(set({ x: 0.7e18, expected: -0.514573172829758229e18 }));\n        sets.push(set({ x: 0.8e18, expected: -0.321928094887362334e18 }));\n        sets.push(set({ x: 0.9e18, expected: -0.152003093445049973e18 }));\n        sets.push(set({ x: 1.125e18, expected: 0.169925001442312346e18 }));\n        sets.push(set({ x: E, expected: 1_442695040888963394 }));\n        sets.push(set({ x: PI, expected: 1_651496129472318782 }));\n        sets.push(set({ x: 1e24, expected: 19_931568569324174075 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, expected: 195_205294292027477728 }));\n        sets.push(set({ x: MAX_SD59x18, expected: 195_205294292027477728 }));\n        return sets;\n    }\n\n    function test_Log2_NotPowerOfTwo() external parameterizedTest(notPowerOfTwo_Sets()) whenNotZero whenPositive {\n        SD59x18 actual = log2(s.x);\n        assertEq(actual, s.expected, \"SD59x18 log2\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/log2/log2.tree",
    "content": "log2.t.sol\n├── when x is zero\n│  └── it should revert\n└── when x is not zero\n   ├── when x is negative\n   │  └── it should revert\n   └── when x is positive\n      ├── when x is a power of two\n      │  └── it should return the correct value\n      └── when x is not a power of two\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/mul/mul.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { PRBMath_MulDiv18_Overflow } from \"src/Common.sol\";\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, MAX_SD59x18, MAX_WHOLE_SD59x18, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Mul_InputTooSmall, PRBMath_SD59x18_Mul_Overflow } from \"src/sd59x18/Errors.sol\";\nimport { mul } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Mul_Unit_Test is SD59x18_Unit_Test {\n    function oneOperandZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 + sd(1), y: 0, expected: 0 }));\n        sets.push(set({ x: 0, y: MIN_SD59x18 + sd(1), expected: 0 }));\n        sets.push(set({ x: 0, y: MAX_SD59x18, expected: 0 }));\n        sets.push(set({ x: MAX_SD59x18, y: 0, expected: 0 }));\n        return sets;\n    }\n\n    function test_Mul_OneOperandZero() external parameterizedTest(oneOperandZero_Sets()) {\n        assertEq(mul(s.x, s.y), s.expected, \"SD59x18 mul\");\n        assertEq(s.x * s.y, s.expected, \"SD59x18 *\");\n    }\n\n    modifier whenNeitherOperandZero() {\n        _;\n    }\n\n    function test_RevertWhen_OneOperandMinSD59x18_Function() external whenNeitherOperandZero {\n        SD59x18 x = MIN_SD59x18;\n        SD59x18 y = sd(0.000000000000000001e18);\n        vm.expectRevert(PRBMath_SD59x18_Mul_InputTooSmall.selector);\n        mul(x, y);\n    }\n\n    function test_RevertWhen_OneOperandMinSD59x18_Operator() external whenNeitherOperandZero {\n        SD59x18 x = sd(0.000000000000000001e18);\n        SD59x18 y = MIN_SD59x18;\n        vm.expectRevert(PRBMath_SD59x18_Mul_InputTooSmall.selector);\n        x * y;\n    }\n\n    modifier whenNeitherOperandMinSD59x18() {\n        _;\n    }\n\n    function test_RevertWhen_ResultOverflowSD59x18_A() external whenNeitherOperandZero whenNeitherOperandMinSD59x18 {\n        SD59x18 x = NEGATIVE_SQRT_MAX_SD59x18;\n        SD59x18 y = NEGATIVE_SQRT_MAX_SD59x18 - sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Mul_Overflow.selector, x, y));\n        mul(x, y);\n    }\n\n    function test_RevertWhen_ResultOverflowSD59x18_B() external whenNeitherOperandZero whenNeitherOperandMinSD59x18 {\n        SD59x18 x = SQRT_MAX_SD59x18;\n        SD59x18 y = SQRT_MAX_SD59x18 + sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Mul_Overflow.selector, x, y));\n        mul(x, y);\n    }\n\n    modifier whenResultDoesNotOverflowSD59x18() {\n        _;\n    }\n\n    function resultOverflowUint256_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 + sd(1), y: MIN_SD59x18 + sd(1), expected: NIL }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, y: MIN_WHOLE_SD59x18, expected: NIL }));\n        sets.push(set({ x: NEGATIVE_SQRT_MAX_UD60x18 - sd(1), y: NEGATIVE_SQRT_MAX_UD60x18 - sd(1), expected: NIL }));\n        sets.push(set({ x: SQRT_MAX_UD60x18 + sd(1), y: SQRT_MAX_UD60x18 + sd(1), expected: NIL }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18, y: MAX_WHOLE_SD59x18, expected: NIL }));\n        sets.push(set({ x: MAX_SD59x18, y: MAX_SD59x18, expected: NIL }));\n        return sets;\n    }\n\n    function test_RevertWhen_ResultOverflowUint256()\n        external\n        parameterizedTest(resultOverflowUint256_Sets())\n        whenNeitherOperandZero\n        whenNeitherOperandMinSD59x18\n        whenResultDoesNotOverflowSD59x18\n    {\n        vm.expectRevert(\n            abi.encodeWithSelector(\n                PRBMath_MulDiv18_Overflow.selector,\n                s.x.lt(ZERO) ? s.x.uncheckedUnary() : s.x,\n                s.y.lt(ZERO) ? s.y.uncheckedUnary() : s.y\n            )\n        );\n        mul(s.x, s.y);\n    }\n\n    modifier whenResultDoesNotOverflowUint256() {\n        _;\n    }\n\n    function operandsSameSign_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 + sd(0.5e18 + 1), y: -0.000000000000000001e18, expected: MAX_SCALED_SD59x18 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18 + sd(0.5e18), y: -0.000000000000000001e18, expected: MAX_SCALED_SD59x18 - sd(1) }));\n        sets.push(set({ x: -1e24, y: -1e20, expected: 1e26 }));\n        sets.push(set({ x: -12_983.989e18, y: -782.99e18, expected: 1_016_6333.54711e18 }));\n        sets.push(set({ x: -9_817e18, y: -2_348e18, expected: 23_050_316e18 }));\n        sets.push(set({ x: -314.271e18, y: -188.19e18, expected: 59_142.65949e18 }));\n        sets.push(set({ x: -18.3e18, y: -12.04e18, expected: 220.332e18 }));\n        sets.push(set({ x: NEGATIVE_PI, y: NEGATIVE_E, expected: 8_539734222673567063 }));\n        sets.push(set({ x: -2.098e18, y: -1.119e18, expected: 2.347662e18 }));\n        sets.push(set({ x: -1e18, y: -1e18, expected: 1e18 }));\n        sets.push(set({ x: -0.01e18, y: -0.05e18, expected: 0.0005e18 }));\n        sets.push(set({ x: -0.001e18, y: -0.01e18, expected: 0.00001e18 }));\n        sets.push(set({ x: -0.00001e18, y: -0.00001e18, expected: 0.0000000001e18 }));\n        sets.push(set({ x: -0.000000001e18, y: -0.000000001e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: -0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: -0.000000000000000006e18, y: -0.1e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000006e18, y: 0.1e18, expected: 0 }));\n        sets.push(set({ x: 0.000000001e18, y: 0.000000001e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 0.00001e18, y: 0.00001e18, expected: 0.0000000001e18 }));\n        sets.push(set({ x: 0.001e18, y: 0.01e18, expected: 0.00001e18 }));\n        sets.push(set({ x: 0.01e18, y: 0.05e18, expected: 0.0005e18 }));\n        sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 2.098e18, y: 1.119e18, expected: 2.347662e18 }));\n        sets.push(set({ x: PI, y: E, expected: 8_539734222673567063 }));\n        sets.push(set({ x: 18.3e18, y: 12.04e18, expected: 220.332e18 }));\n        sets.push(set({ x: 314.271e18, y: 188.19e18, expected: 59_142.65949e18 }));\n        sets.push(set({ x: 9_817e18, y: 2_348e18, expected: 23_050_316e18 }));\n        sets.push(set({ x: 12_983.989e18, y: 782.99e18, expected: 1_016_6333.54711e18 }));\n        sets.push(set({ x: 1e24, y: 1e20, expected: 1e26 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18 - sd(0.5e18), y: 0.000000000000000001e18, expected: MAX_SCALED_SD59x18 - sd(1) }));\n        sets.push(set({ x: MAX_SD59x18 - sd(0.5e18), y: 0.000000000000000001e18, expected: MAX_SCALED_SD59x18 }));\n        return sets;\n    }\n\n    function test_Mul_OperandsSameSign()\n        external\n        parameterizedTest(operandsSameSign_Sets())\n        whenNeitherOperandZero\n        whenNeitherOperandMinSD59x18\n        whenResultDoesNotOverflowSD59x18\n        whenResultDoesNotOverflowUint256\n    {\n        assertEq(mul(s.x, s.y), s.expected, \"SD59x18 mul\");\n        assertEq(s.x * s.y, s.expected, \"SD59x18 *\");\n    }\n\n    function operandsDifferentSigns_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 + sd(0.5e18 + 1), y: 0.000000000000000001e18, expected: MIN_SCALED_SD59x18 }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18 + sd(0.5e18), y: 0.000000000000000001e18, expected: MIN_SCALED_SD59x18 + sd(1) }));\n        sets.push(set({ x: -1e24, y: 1e20, expected: -1e26 }));\n        sets.push(set({ x: -12_983.989e18, y: 782.99e18, expected: -1_016_6333.54711e18 }));\n        sets.push(set({ x: -9_817e18, y: 2_348e18, expected: -23_050_316e18 }));\n        sets.push(set({ x: -314.271e18, y: 188.19e18, expected: -59_142.65949e18 }));\n        sets.push(set({ x: -18.3e18, y: 12.04e18, expected: -220.332e18 }));\n        sets.push(set({ x: NEGATIVE_PI, y: E, expected: -8_539734222673567063 }));\n        sets.push(set({ x: -2.098e18, y: 1.119e18, expected: -2.347662e18 }));\n        sets.push(set({ x: -1e18, y: 1e18, expected: -1e18 }));\n        sets.push(set({ x: -0.01e18, y: 0.05e18, expected: -0.0005e18 }));\n        sets.push(set({ x: -0.001e18, y: 0.01e18, expected: -0.00001e18 }));\n        sets.push(set({ x: -0.00001e18, y: 0.00001e18, expected: -0.0000000001e18 }));\n        sets.push(set({ x: -0.000000001e18, y: 0.000000001e18, expected: -0.000000000000000001e18 }));\n        sets.push(set({ x: -0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: -0.000000000000000006e18, y: 0.1e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: -0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000006e18, y: -0.1e18, expected: 0 }));\n        sets.push(set({ x: 0.000000001e18, y: -0.000000001e18, expected: -0.000000000000000001e18 }));\n        sets.push(set({ x: 0.00001e18, y: -0.00001e18, expected: -0.0000000001e18 }));\n        sets.push(set({ x: 0.001e18, y: -0.01e18, expected: -0.00001e18 }));\n        sets.push(set({ x: 0.01e18, y: -0.05e18, expected: -0.0005e18 }));\n        sets.push(set({ x: 1e18, y: -1e18, expected: -1e18 }));\n        sets.push(set({ x: 2.098e18, y: -1.119e18, expected: -2.347662e18 }));\n        sets.push(set({ x: PI, y: NEGATIVE_E, expected: -8_539734222673567063 }));\n        sets.push(set({ x: 18.3e18, y: -12.04e18, expected: -220.332e18 }));\n        sets.push(set({ x: 314.271e18, y: -188.19e18, expected: -59_142.65949e18 }));\n        sets.push(set({ x: 9_817e18, y: -2_348e18, expected: -23_050_316e18 }));\n        sets.push(set({ x: 12_983.989e18, y: -782.99e18, expected: -1_016_6333.54711e18 }));\n        sets.push(set({ x: 1e24, y: -1e20, expected: -1e26 }));\n        sets.push(set({ x: MAX_WHOLE_SD59x18 - sd(0.5e18), y: -0.000000000000000001e18, expected: MIN_SCALED_SD59x18 + sd(1) }));\n        sets.push(set({ x: MAX_SD59x18 - sd(0.5e18), y: -0.000000000000000001e18, expected: MIN_SCALED_SD59x18 }));\n        return sets;\n    }\n\n    function test_Mul_OperandsDifferentSign()\n        external\n        parameterizedTest(operandsDifferentSigns_Sets())\n        whenNeitherOperandZero\n        whenNeitherOperandMinSD59x18\n        whenResultDoesNotOverflowSD59x18\n        whenResultDoesNotOverflowUint256\n    {\n        assertEq(mul(s.x, s.y), s.expected, \"SD59x18 mul\");\n        assertEq(s.x * s.y, s.expected, \"SD59x18 *\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/mul/mul.tree",
    "content": "div.t.sol\n├── when one of the operands is zero\n│  └── it should return zero\n└── when neither operand is zero\n   ├── when one of the operands is min sd59x18\n   │  └── it should revert\n   └── when neither operand is min sd59x18\n      ├── when the result overflows sd59x18\n      │  └── it should revert\n      └── when the result does not overflow sd59x18\n        ├── when the result overflows uint256\n        │  └── it should revert\n        └── when the result does not overflow uint256\n           ├── when the operands have the same sign\n           │  └── it should return the correct value\n           └── when the operands do not have different signs\n              └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/pow/pow.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { E, PI, UNIT, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { pow } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Pow_Unit_Test is SD59x18_Unit_Test {\n    function test_Pow_BaseZero_ExponentZero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 y = ZERO;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = UNIT;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    function test_Pow_BaseZero_ExponentNotZero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 y = UNIT;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    modifier whenBaseNotZero() {\n        _;\n    }\n\n    function test_Pow_BaseUnit() external pure whenBaseNotZero {\n        SD59x18 x = UNIT;\n        SD59x18 y = PI;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = UNIT;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    modifier whenBaseNotUnit() {\n        _;\n    }\n\n    function test_Pow_ExponentZero() external pure whenBaseNotZero whenBaseNotUnit {\n        SD59x18 x = PI;\n        SD59x18 y = ZERO;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = UNIT;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    modifier whenExponentNotZero() {\n        _;\n    }\n\n    function test_Pow_ExponentUnit() external pure whenBaseNotZero whenBaseNotUnit whenExponentNotZero {\n        SD59x18 x = PI;\n        SD59x18 y = UNIT;\n        SD59x18 actual = pow(x, y);\n        SD59x18 expected = x;\n        assertEq(actual, expected, \"SD59x18 pow\");\n    }\n\n    modifier whenExponentNotUnit() {\n        _;\n    }\n\n    function negativeExponent_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, y: -0.000000000000000001e18, expected: 1e18 + 40 }));\n        sets.push(set({ x: 0.000000000001e18, y: -4.4e9, expected: 1_000000121576500300 }));\n        sets.push(set({ x: 0.1e18, y: -0.8e18, expected: 6_309573444801932444 }));\n        sets.push(set({ x: 0.24e18, y: -11e18, expected: 6571678_991286039528731186 }));\n        sets.push(set({ x: 0.5e18, y: -0.7373e18, expected: 1_667053032211341971 }));\n        sets.push(set({ x: 0.799291e18, y: -69e18, expected: 5168450_048540730175583501 }));\n        sets.push(set({ x: 1e18, y: -1e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, y: NEGATIVE_PI, expected: 1e18 }));\n        sets.push(set({ x: 2e18, y: -1.5e18, expected: 0.353553390593273762e18 }));\n        sets.push(set({ x: E, y: NEGATIVE_E, expected: 0.065988035845312538e18 }));\n        sets.push(set({ x: E, y: -1.66976e18, expected: 0.18829225035644931e18 }));\n        sets.push(set({ x: PI, y: -1.5e18, expected: 0.179587122125166564e18 }));\n        sets.push(set({ x: 11e18, y: -28.5e18, expected: 0 }));\n        sets.push(set({ x: 32.15e18, y: -23.99e18, expected: 0 }));\n        sets.push(set({ x: 406e18, y: -0.25e18, expected: 0.222776046060941016e18 }));\n        sets.push(set({ x: 1729e18, y: -0.98e18, expected: 0.00067136841637396e18 }));\n        sets.push(set({ x: 33441e18, y: -2.1891e18, expected: 0.000000000124709713e18 }));\n        sets.push(set({ x: 2 ** 128 * 1e18 - 1, y: -1e18, expected: 0 }));\n        sets.push(set({ x: 2 ** 192 * 1e18 - 1, y: -1e18, expected: 0 }));\n        return sets;\n    }\n\n    function test_Pow_NegativeExponent()\n        external\n        parameterizedTest(negativeExponent_Sets())\n        whenBaseNotZero\n        whenBaseNotUnit\n        whenExponentNotZero\n        whenExponentNotUnit\n    {\n        SD59x18 actual = pow(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 pow\");\n    }\n\n    function positiveExponent_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0.99999999999999996e18 }));\n        sets.push(set({ x: 1e6, y: 4.4e9, expected: 0.99999987842351448e18 }));\n        sets.push(set({ x: 0.1e18, y: 0.8e18, expected: 0.158489319246111349e18 }));\n        sets.push(set({ x: 0.24e18, y: 11e18, expected: 0.000000152168114316e18 }));\n        sets.push(set({ x: 0.5e18, y: 0.7373e18, expected: 0.59986094064056398e18 }));\n        sets.push(set({ x: 0.799291e18, y: 69e18, expected: 0.000000193481602919e18 }));\n        sets.push(set({ x: 1e18, y: 2e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, y: PI, expected: 1e18 }));\n        sets.push(set({ x: 2e18, y: 1.5e18, expected: 2_828427124746190097 }));\n        sets.push(set({ x: E, y: E, expected: 15_154262241479263793 }));\n        sets.push(set({ x: E, y: 1.66976e18, expected: 5_310893029888037560 }));\n        sets.push(set({ x: PI, y: PI, expected: 36_462159607207910473 }));\n        sets.push(set({ x: 11e18, y: 28.5e18, expected: 478290249106383504389245497918_050372801213485439 }));\n        sets.push(set({ x: 32.15e18, y: 23.99e18, expected: 1436387590627448555101723413293079116_943375472179194989 }));\n        sets.push(set({ x: 406e18, y: 0.25e18, expected: 4_488812947719016318 }));\n        sets.push(set({ x: 1729e18, y: 0.98e18, expected: 1489_495149922256917866 }));\n        sets.push(set({ x: 33441e18, y: 2.1891e18, expected: 8018621589_681923269491820156 }));\n        sets.push(\n            set({\n                x: 340282366920938463463374607431768211455e18,\n                y: 1e18 + 1,\n                expected: 340282366920938487757736552507248225013_000000000004316573\n            })\n        );\n        sets.push(\n            set({ x: 2 ** 192 * 1e18 - 1, y: 1e18 - 1, expected: 6277101735386679823624773486129835356722228023657461399187e18 })\n        );\n        return sets;\n    }\n\n    function test_Pow_PositiveExponent()\n        external\n        parameterizedTest(positiveExponent_Sets())\n        whenBaseNotZero\n        whenBaseNotUnit\n        whenExponentNotZero\n        whenExponentNotUnit\n    {\n        SD59x18 actual = pow(s.x, s.y);\n        assertEq(actual, s.expected, \"SD59x18 pow\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/pow/pow.tree",
    "content": "pow.t.sol\n├── when the base is zero\n│  ├── when the exponent is zero\n│  │  └── it should return the unit number\n│  └── when the exponent is not zero\n│     └── it should return zero\n└── when the base is not zero\n   ├── when the base is the unit number\n   │  └── it should return the unit number\n   └── when the base is not the unit number\n      ├── when the exponent is zero\n      │  └── it should return the base\n      └── when the exponent is not zero\n         ├── when the exponent is the unit number\n         │  └── it should return the base\n         └── when the exponent is not the unit number\n            ├── when the exponent is negative\n            │  └── it should return the correct value\n            └── when the exponent is positive\n               └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/powu/powu.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { PRBMath_MulDiv18_Overflow } from \"src/Common.sol\";\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport {\n    E,\n    MAX_SD59x18,\n    MAX_WHOLE_SD59x18,\n    MIN_SD59x18,\n    MIN_WHOLE_SD59x18,\n    PI,\n    uMAX_SD59x18,\n    ZERO\n} from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Powu_Overflow } from \"src/sd59x18/Errors.sol\";\nimport { powu } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Powu_Unit_Test is SD59x18_Unit_Test {\n    function test_Powu_BaseAndExponentZero() external pure {\n        SD59x18 x = ZERO;\n        uint256 y = 0;\n        SD59x18 actual = powu(x, y);\n        SD59x18 expected = sd(1e18);\n        assertEq(actual, expected, \"SD59x18 powu\");\n    }\n\n    function baseZeroExponentNotZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: 1e18, expected: 0 }));\n        sets.push(set({ x: 0, y: 2, expected: 0 }));\n        sets.push(set({ x: 0, y: 3, expected: 0 }));\n        return sets;\n    }\n\n    function test_Powu_BaseZeroExponentNotZero() external parameterizedTest(baseZeroExponentNotZero_Sets()) {\n        SD59x18 actual = powu(s.x, sdToUint(s.y));\n        assertEq(actual, s.expected, \"SD59x18 powu\");\n    }\n\n    modifier whenBaseNotZero() {\n        _;\n    }\n\n    function exponentZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 + sd(1), expected: 1e18 }));\n        sets.push(set({ x: NEGATIVE_PI, expected: 1e18 }));\n        sets.push(set({ x: -1e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: PI, expected: 1e18 }));\n        sets.push(set({ x: MAX_SD59x18 - sd(1), expected: 1e18 }));\n        return sets;\n    }\n\n    function test_Powu_ExponentZero() external parameterizedTest(exponentZero_Sets()) whenBaseNotZero {\n        SD59x18 actual = powu(s.x, sdToUint(s.y));\n        assertEq(actual, s.expected, \"SD59x18 powu\");\n    }\n\n    modifier whenExponentNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_ResultOverflowUint256() external whenBaseNotZero whenExponentNotZero {\n        SD59x18 x = MIN_SD59x18 + sd(1);\n        uint256 y = 2;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_MulDiv18_Overflow.selector, uint256(uMAX_SD59x18), uint256(uMAX_SD59x18)));\n        powu(x, y);\n    }\n\n    modifier whenResultDoesNotOverflowUint256() {\n        _;\n    }\n\n    function test_RevertWhen_ResultUnderflowSD59x18()\n        external\n        whenBaseNotZero\n        whenExponentNotZero\n        whenResultDoesNotOverflowUint256\n    {\n        SD59x18 x = NEGATIVE_SQRT_MAX_SD59x18 - sd(1);\n        uint256 y = 2;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Powu_Overflow.selector, x, y));\n        powu(x, y);\n    }\n\n    function test_RevertWhen_ResultOverflowSD59x18() external whenBaseNotZero whenExponentNotZero whenResultDoesNotOverflowUint256 {\n        SD59x18 x = SQRT_MAX_SD59x18 + sd(1);\n        uint256 y = 2;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Powu_Overflow.selector, x, y));\n        powu(x, y);\n    }\n\n    modifier whenResultDoesNotOverflowOrUnderflowSD59x18() {\n        _;\n    }\n\n    function negativeBase_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: MIN_SD59x18 + sd(1), y: 1, expected: MIN_SD59x18 + sd(1) }));\n        sets.push(set({ x: MIN_WHOLE_SD59x18, y: 1, expected: MIN_WHOLE_SD59x18 }));\n        sets.push(\n            set({\n                x: NEGATIVE_SQRT_MAX_SD59x18,\n                y: 2,\n                expected: 57896044618658097711785492504343953926634992332789893003858_354368578996153260\n            })\n        );\n        sets.push(\n            set({\n                x: -38685626227668133590.597631999999999999e18,\n                y: 3,\n                expected: -57896044618658097711785492504343953922145259302939748254975_940481744194640509\n            })\n        );\n        sets.push(set({ x: -1e24, y: 3, expected: -1e36 }));\n        sets.push(set({ x: -6452.166e18, y: 7, expected: -4655204093726194074224341678_62736844121311696 }));\n        sets.push(\n            set({ x: -478.77e18, y: 20, expected: 400441047687151121501368529571950234763284476825512183_793320584974037932 })\n        );\n        sets.push(set({ x: -100e18, y: 4, expected: 1e26 }));\n        sets.push(set({ x: -5.491e18, y: 19, expected: -113077820843204_476043049664958463 }));\n        sets.push(set({ x: NEGATIVE_E, y: 2, expected: 7_389056098930650225 }));\n        sets.push(set({ x: NEGATIVE_PI, y: 3, expected: -31_006276680299820158 }));\n        sets.push(set({ x: -2e18, y: 100, expected: 1267650600228_229401496703205376e18 }));\n        sets.push(set({ x: -2e18, y: 5, expected: -32e18 }));\n        sets.push(set({ x: -1e18, y: 1, expected: -1e18 }));\n        sets.push(set({ x: -0.1e18, y: 2, expected: 0.01e18 }));\n        sets.push(set({ x: -0.001e18, y: 3, expected: -0.000000001e18 }));\n        return sets;\n    }\n\n    function test_Powu_NegativeBase()\n        external\n        parameterizedTest(negativeBase_Sets())\n        whenBaseNotZero\n        whenExponentNotZero\n        whenResultDoesNotOverflowUint256\n        whenResultDoesNotOverflowOrUnderflowSD59x18\n    {\n        SD59x18 actual = powu(s.x, sdToUint(s.y));\n        assertEq(actual, s.expected, \"SD59x18 powu\");\n    }\n\n    function positiveBase_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.001e18, y: 3, expected: 1e9 }));\n        sets.push(set({ x: 0.1e18, y: 2, expected: 1e16 }));\n        sets.push(set({ x: 1e18, y: 1, expected: 1e18 }));\n        sets.push(set({ x: 2e18, y: 5, expected: 32e18 }));\n        sets.push(set({ x: 2e18, y: 100, expected: 1267650600228_229401496703205376e18 }));\n        sets.push(set({ x: E, y: 2, expected: 7_389056098930650225 }));\n        sets.push(set({ x: PI, y: 3, expected: 31_006276680299820158 }));\n        sets.push(set({ x: 5.491e18, y: 19, expected: 113077820843204_476043049664958463 }));\n        sets.push(set({ x: 100e18, y: 4, expected: 1e26 }));\n        sets.push(set({ x: 478.77e18, y: 20, expected: 400441047687151121501368529571950234763284476825512183793320584974037932 }));\n        sets.push(set({ x: 6452.166e18, y: 7, expected: 4655204093726194074224341678_62736844121311696 }));\n        sets.push(set({ x: 1e24, y: 3, expected: 1e36 }));\n        sets.push(\n            set({\n                x: 38685626227668133590.597631999999999999e18,\n                y: 3,\n                expected: 57896044618658097711785492504343953922145259302939748254975_940481744194640509\n            })\n        );\n        sets.push(\n            set({\n                x: SQRT_MAX_SD59x18, y: 2, expected: 57896044618658097711785492504343953926634992332789893003858_354368578996153260\n            })\n        );\n        sets.push(set({ x: MAX_WHOLE_SD59x18, y: 1, expected: MAX_WHOLE_SD59x18 }));\n        sets.push(set({ x: MAX_SD59x18, y: 1, expected: MAX_SD59x18 }));\n        return sets;\n    }\n\n    function test_Powu_PositiveBase()\n        external\n        parameterizedTest(positiveBase_Sets())\n        whenBaseNotZero\n        whenExponentNotZero\n        whenResultDoesNotOverflowUint256\n        whenResultDoesNotOverflowOrUnderflowSD59x18\n    {\n        SD59x18 actual = powu(s.x, sdToUint(s.y));\n        assertEq(actual, s.expected, \"SD59x18 powu\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/powu/powu.tree",
    "content": "powu.t.sol\n├── when the base is zero\n│  ├── when the exponent is zero\n│  │  └── it should return the unit number\n│  └── when the exponent is not zero\n│     └── it should return zero\n└── when the base is not zero\n   ├── when the exponent is zero\n   │  └── it should return the unit number\n   └── when the exponent is not zero\n      ├── when the result overflows uint256\n      │  └── it should revert\n      └── when the result does not overflow uint256\n         ├── when the result overflows or underflows sd59x18\n         │  └── it should revert\n         └── when the result does not overflow or underflow sd59x18\n            ├── when the base is negative\n            │  └── it should return the correct value\n            └── when the base is positive\n               └── it should return the correct value\n"
  },
  {
    "path": "test/unit/sd59x18/math/sqrt/sqrt.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { sd } from \"src/sd59x18/Casting.sol\";\nimport { E, PI, ZERO } from \"src/sd59x18/Constants.sol\";\nimport { PRBMath_SD59x18_Sqrt_NegativeInput, PRBMath_SD59x18_Sqrt_Overflow } from \"src/sd59x18/Errors.sol\";\nimport { sqrt } from \"src/sd59x18/Math.sol\";\nimport { SD59x18 } from \"src/sd59x18/ValueType.sol\";\n\nimport { SD59x18_Unit_Test } from \"../../SD59x18.t.sol\";\n\ncontract Sqrt_Unit_Test is SD59x18_Unit_Test {\n    function test_Sqrt_Zero() external pure {\n        SD59x18 x = ZERO;\n        SD59x18 actual = sqrt(x);\n        SD59x18 expected = ZERO;\n        assertEq(actual, expected, \"SD59x18 sqrt\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_Negative() external whenNotZero {\n        SD59x18 x = sd(-1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Sqrt_NegativeInput.selector, x));\n        sqrt(x);\n    }\n\n    modifier whenPositive() {\n        _;\n    }\n\n    function test_RevertWhen_GtMaxPermitted() external whenNotZero whenPositive {\n        SD59x18 x = MAX_SCALED_SD59x18 + sd(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_SD59x18_Sqrt_Overflow.selector, x));\n        sqrt(x);\n    }\n\n    modifier whenLteMaxPermitted() {\n        _;\n    }\n\n    function sqrt_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 0.000000001e18 }));\n        sets.push(set({ x: 0.000000000000001e18, expected: 0.000000031622776601e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, expected: 1_414213562373095048 }));\n        sets.push(set({ x: E, expected: 1_648721270700128146 }));\n        sets.push(set({ x: 3e18, expected: 1_732050807568877293 }));\n        sets.push(set({ x: PI, expected: 1_772453850905516027 }));\n        sets.push(set({ x: 4e18, expected: 2e18 }));\n        sets.push(set({ x: 16e18, expected: 4e18 }));\n        sets.push(set({ x: 1e35, expected: 316227766_016837933199889354 }));\n        sets.push(set({ x: 12489131238983290393813_123784889921092801, expected: 111754781727_598977910452220959 }));\n        sets.push(set({ x: 1889920002192904839344128288891377_732371920009212883, expected: 43473210166640613973238162807779776 }));\n        sets.push(set({ x: 1e58, expected: 1e38 }));\n        sets.push(set({ x: 5e58, expected: 223606797749978969640_917366873127623544 }));\n        sets.push(set({ x: MAX_SCALED_SD59x18, expected: 240615969168004511545_033772477625056927 }));\n        return sets;\n    }\n\n    function test_Sqrt() external parameterizedTest(sqrt_Sets()) whenNotZero whenPositive whenLteMaxPermitted {\n        SD59x18 actual = sqrt(s.x);\n        assertEq(actual, s.expected, \"SD59x18 sqrt\");\n    }\n}\n"
  },
  {
    "path": "test/unit/sd59x18/math/sqrt/sqrt.tree",
    "content": "sqrt.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   ├── when x is negative\n   │  └── it should revert\n   └── when x is positive\n      ├── when x is greater than the maximum permitted\n      │  └── it should revert\n      └── when x is less than or equal to the maximum permitted\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/UD60x18.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { console2 } from \"forge-std/src/console2.sol\";\n\nimport { ZERO } from \"src/ud60x18/Constants.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { Base_Test } from \"../../Base.t.sol\";\n\n/// @notice Common logic needed by all UD60x18 unit tests.\nabstract contract UD60x18_Unit_Test is Base_Test {\n    /*//////////////////////////////////////////////////////////////////////////\n                                      CONSTANTS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    UD60x18 internal constant MAX_SCALED_UD60x18 = UD60x18.wrap(115792089237316195423570985008687907853269_984665640564039457);\n    UD60x18 internal constant SQRT_MAX_UD60x18 = UD60x18.wrap(340282366920938463463374607431_768211455999999999);\n\n    /// @dev This is needed to be used as the `expected` parameter of {set}. Solidity functions cannot be overridden\n    /// to have two implementations that each has two \"int256\" arguments.\n    UD60x18 internal constant NIL = ZERO;\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                       STRUCTS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    struct Set {\n        UD60x18 x;\n        UD60x18 y;\n        UD60x18 expected;\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                     VARIABLES\n    //////////////////////////////////////////////////////////////////////////*/\n\n    Set internal s;\n    Set[] internal sets;\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                      MODIFIERS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    modifier parameterizedTest(Set[] memory testSets) {\n        uint256 length = testSets.length;\n        for (uint256 i = 0; i < length; ++i) {\n            s = testSets[i];\n            _;\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                              CONSTANT HELPER FUNCTIONS\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function logUd(UD60x18 p0) internal pure {\n        console2.logUint(p0.unwrap());\n    }\n\n    function logUd(string memory p0, UD60x18 p1) internal pure {\n        console2.log(p0, p1.unwrap());\n    }\n\n    function set(uint256 x) internal pure returns (Set memory) {\n        return Set({ x: ud(x), y: ZERO, expected: ZERO });\n    }\n\n    function set(UD60x18 x) internal pure returns (Set memory) {\n        return Set({ x: x, y: ZERO, expected: ZERO });\n    }\n\n    function set(uint256 x, uint256 expected) internal pure returns (Set memory) {\n        return Set({ x: ud(x), y: ZERO, expected: ud(expected) });\n    }\n\n    function set(uint256 x, UD60x18 expected) internal pure returns (Set memory) {\n        return Set({ x: ud(x), y: ZERO, expected: expected });\n    }\n\n    function set(UD60x18 x, uint256 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: ZERO, expected: ud(expected) });\n    }\n\n    function set(UD60x18 x, UD60x18 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: ZERO, expected: expected });\n    }\n\n    function set(uint256 x, uint256 y, uint256 expected) internal pure returns (Set memory) {\n        return Set({ x: ud(x), y: ud(y), expected: ud(expected) });\n    }\n\n    function set(uint256 x, uint256 y, UD60x18 expected) internal pure returns (Set memory) {\n        return Set({ x: ud(x), y: ud(y), expected: expected });\n    }\n\n    function set(uint256 x, UD60x18 y, uint256 expected) internal pure returns (Set memory) {\n        return Set({ x: ud(x), y: y, expected: ud(expected) });\n    }\n\n    function set(uint256 x, UD60x18 y, UD60x18 expected) internal pure returns (Set memory) {\n        return Set({ x: ud(x), y: y, expected: expected });\n    }\n\n    function set(UD60x18 x, uint256 y, uint256 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: ud(y), expected: ud(expected) });\n    }\n\n    function set(UD60x18 x, UD60x18 y, uint256 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: y, expected: ud(expected) });\n    }\n\n    function set(UD60x18 x, uint256 y, UD60x18 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: ud(y), expected: expected });\n    }\n\n    function set(UD60x18 x, UD60x18 y, UD60x18 expected) internal pure returns (Set memory) {\n        return Set({ x: x, y: y, expected: expected });\n    }\n\n    function ud(uint256 x) internal pure returns (UD60x18 result) {\n        result = UD60x18.wrap(x);\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/conversion/convert-from/convertFrom.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { E, MAX_WHOLE_UD60x18, MAX_UD60x18, PI } from \"src/ud60x18/Constants.sol\";\nimport { convert } from \"src/ud60x18/Conversions.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract ConvertFrom_Unit_Test is UD60x18_Unit_Test {\n    function ltUnit_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0 }));\n        sets.push(set({ x: 1 }));\n        sets.push(set({ x: 1e18 - 1 }));\n        return sets;\n    }\n\n    function test_ConvertFrom_LtUnit() external parameterizedTest(ltUnit_Sets()) {\n        uint256 actual = convert(s.x);\n        uint256 expected = 0;\n        assertEq(actual, expected, \"UD60x18 convertFrom\");\n    }\n\n    modifier whenGteUnit() {\n        _;\n    }\n\n    function gteUnit_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 1e18 + 1, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 2e18 - 1, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 2e18, expected: 0.000000000000000002e18 }));\n        sets.push(set({ x: 2e18 + 1, expected: 0.000000000000000002e18 }));\n        sets.push(set({ x: E, expected: 0.000000000000000002e18 }));\n        sets.push(set({ x: PI, expected: 0.000000000000000003e18 }));\n        sets.push(set({ x: 1729e18, expected: 0.000000000000001729e18 }));\n        sets.push(set({ x: 4.2e45, expected: 4.2e27 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: MAX_SCALED_UD60x18 }));\n        sets.push(set({ x: MAX_UD60x18, expected: MAX_SCALED_UD60x18 }));\n        return sets;\n    }\n\n    function test_ConvertFrom() external parameterizedTest(gteUnit_Sets()) whenGteUnit {\n        uint256 actual = convert(s.x);\n        uint256 expected = s.expected.unwrap();\n        assertEq(actual, expected, \"UD60x18 convertFrom\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/conversion/convert-from/convertFrom.tree",
    "content": "convertFrom.t.sol\n├── when x is less than the unit number\n│  └── it should revert\n└── when x is greater than or equal to the unit number\n   └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/conversion/convert-to/convertTo.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { MAX_WHOLE_UD60x18 } from \"src/ud60x18/Constants.sol\";\nimport { convert } from \"src/ud60x18/Conversions.sol\";\nimport { PRBMath_UD60x18_Convert_Overflow } from \"src/ud60x18/Errors.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract ConvertTo_Unit_Test is UD60x18_Unit_Test {\n    function test_RevertWhen_GtMaxPermitted() external {\n        uint256 x = MAX_SCALED_UD60x18.unwrap() + 1;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Convert_Overflow.selector, x));\n        convert(x);\n    }\n\n    modifier whenLteMaxPermitted() {\n        _;\n    }\n\n    function convertTo_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e18 }));\n        sets.push(set({ x: 0.000000000000000002e18, expected: 2e18 }));\n        sets.push(set({ x: 0.000000000000001729e18, expected: 1729e18 }));\n        sets.push(set({ x: 1e18, expected: 1e36 }));\n        sets.push(set({ x: 5e18, expected: 5e36 }));\n        sets.push(set({ x: 2.7182e38, expected: 2.7182e56 }));\n        sets.push(set({ x: 3.1415e42, expected: 3.1415e60 }));\n        sets.push(set({ x: MAX_SCALED_UD60x18, expected: MAX_WHOLE_UD60x18 }));\n        return sets;\n    }\n\n    function test_ConvertTo() external parameterizedTest(convertTo_Sets()) whenLteMaxPermitted {\n        UD60x18 x = convert(s.x.unwrap());\n        assertEq(x, s.expected, \"UD60x18 convertTo\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/conversion/convert-to/convertTo.tree",
    "content": "convertT.t.sol\n├── when x is greater than the maximum permitted\n│  └── it should revert\n└── when x is less than or equal to the maximum permitted\n   └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/avg/avg.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { MAX_UD60x18, MAX_WHOLE_UD60x18, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { avg } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Avg_Unit_Test is UD60x18_Unit_Test {\n    function test_Avg_BothOperandsZero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 y = ZERO;\n        UD60x18 actual = avg(x, y);\n        UD60x18 expected = ZERO;\n        assertEq(actual, expected, \"UD60x18 avg\");\n    }\n\n    function onlyOneOperandZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: 3e18, expected: 1.5e18 }));\n        sets.push(set({ x: 3e18, y: 0, expected: 1.5e18 }));\n        return sets;\n    }\n\n    function test_Avg_OnlyOneOperandZero() external parameterizedTest(onlyOneOperandZero_Sets()) {\n        UD60x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"UD60x18 avg\");\n    }\n\n    modifier whenNeitherOperandZero() {\n        _;\n    }\n\n    function bothOperandsEven_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 2, y: 4, expected: 3 }));\n        sets.push(set({ x: 2e18, y: 2e18, expected: 2e18 }));\n        sets.push(set({ x: 4e18, y: 8e18, expected: 6e18 }));\n        sets.push(set({ x: 100e18, y: 200e18, expected: 150e18 }));\n        sets.push(set({ x: 1e24, y: 1e25, expected: 5.5e24 }));\n        return sets;\n    }\n\n    function test_Avg_NeitherOperandZero_BothOperandsEven()\n        external\n        parameterizedTest(bothOperandsEven_Sets())\n        whenNeitherOperandZero\n    {\n        UD60x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"UD60x18 avg\");\n    }\n\n    function bothOperandsOdd_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1, y: 3, expected: 2 }));\n        sets.push(set({ x: 1e18 + 1, y: 1e18 + 1, expected: 1e18 + 1 }));\n        sets.push(set({ x: 3e18 + 1, y: 7e18 + 1, expected: 5e18 + 1 }));\n        sets.push(set({ x: 99e18 + 1, y: 199e18 + 1, expected: 149e18 + 1 }));\n        sets.push(set({ x: 1e24 + 1, y: 1e25 + 1, expected: 5.5e24 + 1 }));\n        sets.push(set({ x: MAX_UD60x18, y: MAX_UD60x18, expected: MAX_UD60x18 }));\n        return sets;\n    }\n\n    function test_Avg_NeitherOperandZero_BothOperandsOdd()\n        external\n        parameterizedTest(bothOperandsOdd_Sets())\n        whenNeitherOperandZero\n    {\n        UD60x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"UD60x18 avg\");\n    }\n\n    function oneOperandEvenTheOtherOdd_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1, y: 2, expected: 1 }));\n        sets.push(set({ x: 1e18 + 1, y: 2e18, expected: 1.5e18 }));\n        sets.push(set({ x: 3e18 + 1, y: 8e18, expected: 5.5e18 }));\n        sets.push(set({ x: 99e18, y: 200e18, expected: 149.5e18 }));\n        sets.push(set({ x: 1e24 + 1, y: 1e25 + 1e18, expected: 5.5e24 + 0.5e18 }));\n        sets.push(\n            set({\n                x: MAX_UD60x18,\n                y: MAX_WHOLE_UD60x18,\n                expected: 115792089237316195423570985008687907853269984665640564039457_292003956564819967\n            })\n        );\n        return sets;\n    }\n\n    function test_Avg_NeitherOperandZero_OneOperandEvenTheOtherOdd()\n        external\n        parameterizedTest(oneOperandEvenTheOtherOdd_Sets())\n        whenNeitherOperandZero\n    {\n        UD60x18 actual = avg(s.x, s.y);\n        assertEq(actual, s.expected, \"UD60x18 avg\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/avg/avg.tree",
    "content": "avg.t.sol\n├── when both operands are zero\n│  └── it should return zero\n├── when only one operand is zero\n│  └── it should return the correct value\n└── when neither operand is zero\n   ├── when both operands are even\n   │  └── it should return the correct value\n   ├── when both operands are odd\n   │  └── it should return the correct value\n   └── when one operand is even and the other is odd\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/ceil/ceil.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { ud } from \"src/ud60x18/Casting.sol\";\nimport { MAX_WHOLE_UD60x18, PI, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Ceil_Overflow } from \"src/ud60x18/Errors.sol\";\nimport { ceil } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract CeilTest is UD60x18_Unit_Test {\n    function test_Ceil_Zero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 actual = ceil(x);\n        UD60x18 expected = ZERO;\n        assertEq(actual, expected, \"UD60x18 ceil\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_GtMaxPermitted() external whenNotZero {\n        UD60x18 x = MAX_WHOLE_UD60x18 + ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Ceil_Overflow.selector, x));\n        ceil(x);\n    }\n\n    modifier whenLteMaxWholeUD60x18() {\n        _;\n    }\n\n    function ceil_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: 1e18 }));\n        sets.push(set({ x: 0.5e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 1.125e18, expected: 2e18 }));\n        sets.push(set({ x: 2e18, expected: 2e18 }));\n        sets.push(set({ x: PI, expected: 4e18 }));\n        sets.push(set({ x: 4.2e18, expected: 5e18 }));\n        sets.push(set({ x: 1e24, expected: 1e24 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: MAX_WHOLE_UD60x18 }));\n        return sets;\n    }\n\n    function test_Ceil() external parameterizedTest(ceil_Sets()) whenNotZero whenLteMaxWholeUD60x18 {\n        UD60x18 actual = ceil(s.x);\n        assertEq(actual, s.expected, \"UD60x18 ceil\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/ceil/ceil.tree",
    "content": "ceil.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   ├── when x is greater than the maximum permitted\n   │  └── it should revert\n   └── when x is less than or equal to the maximum permitted\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/div/div.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { stdError } from \"forge-std/src/StdError.sol\";\n\nimport { MAX_UD60x18, MAX_WHOLE_UD60x18, PI, uUNIT, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { div } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\nimport { PRBMath_MulDiv_Overflow } from \"src/Common.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Div_Unit_Test is UD60x18_Unit_Test {\n    function test_RevertWhen_DenominatorZero_Function() external {\n        UD60x18 x = ud(1e18);\n        UD60x18 y = ZERO;\n        vm.expectRevert(stdError.divisionError);\n        div(x, y);\n    }\n\n    function test_RevertWhen_DenominatorZero_Operator() external {\n        UD60x18 x = ud(1e18);\n        UD60x18 y = ZERO;\n        vm.expectRevert(stdError.divisionError);\n        x / y;\n    }\n\n    modifier whenDenominatorNotZero() {\n        _;\n    }\n\n    function numeratorZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: 0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0, y: 1e18, expected: 0 }));\n        sets.push(set({ x: 0, y: PI, expected: 0 }));\n        sets.push(set({ x: 0, y: 1e24, expected: 0 }));\n        return sets;\n    }\n\n    function test_Div_NumeratorZero() external parameterizedTest(numeratorZero_Sets()) whenDenominatorNotZero {\n        assertEq(div(s.x, s.y), s.expected, \"UD60x18 div\");\n        assertEq(s.x / s.y, s.expected, \"UD60x18 /\");\n    }\n\n    function test_RevertWhen_ResultOverflowUD60x18_Function() external whenDenominatorNotZero {\n        UD60x18 x = MAX_SCALED_UD60x18 + ud(1);\n        UD60x18 y = ud(0.000000000000000001e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_MulDiv_Overflow.selector, x.unwrap(), uUNIT, y.unwrap()));\n        div(x, y);\n    }\n\n    function test_RevertWhen_ResultOverflowUD60x18_Operator() external whenDenominatorNotZero {\n        UD60x18 x = MAX_SCALED_UD60x18 + ud(1);\n        UD60x18 y = ud(0.000000000000000001e18);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_MulDiv_Overflow.selector, x.unwrap(), uUNIT, y.unwrap()));\n        x / y;\n    }\n\n    modifier whenResultDoesNotOverflowUD60x18() {\n        _;\n    }\n\n    function div_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, y: MAX_UD60x18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: 1.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000001e18, y: 1e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 1e13, y: 1e13, expected: 1e18 }));\n        sets.push(set({ x: 1e13, y: 0.00002e18, expected: 0.5e18 }));\n        sets.push(set({ x: 0.05e18, y: 0.02e18, expected: 2.5e18 }));\n        sets.push(set({ x: 0.1e18, y: 0.01e18, expected: 10e18 }));\n        sets.push(set({ x: 2e18, y: 2e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, y: 5e18, expected: 0.4e18 }));\n        sets.push(set({ x: 4e18, y: 2e18, expected: 2e18 }));\n        sets.push(set({ x: 22e18, y: 7e18, expected: 3_142857142857142857 }));\n        sets.push(set({ x: 100.135e18, y: 100.134e18, expected: 1_000009986617931971 }));\n        sets.push(set({ x: 772.05e18, y: 199.98e18, expected: 3_860636063606360636 }));\n        sets.push(set({ x: 2503e18, y: 918882.11e18, expected: 0.002723962054283546e18 }));\n        sets.push(set({ x: 1e24, y: 1e18, expected: 1e24 }));\n        sets.push(set({ x: MAX_SCALED_UD60x18, y: 0.000000000000000001e18, expected: MAX_WHOLE_UD60x18 }));\n        return sets;\n    }\n\n    function test_Div() external parameterizedTest(div_Sets()) whenDenominatorNotZero whenResultDoesNotOverflowUD60x18 {\n        assertEq(div(s.x, s.y), s.expected, \"UD60x18 div\");\n        assertEq(s.x / s.y, s.expected, \"UD60x18 /\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/div/div.tree",
    "content": "div.t.sol\n├── when the denominator is zero\n│  └── it should revert\n└── when the denominator is not zero\n   ├── when the numerator is zero\n   │  └── it should return zero\n   └── when the numerator is not zero\n      ├── when the result overflows ud60x18\n      │  └── it should revert\n      └── when the result does not overflow ud60x18\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/exp/exp.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { ud } from \"src/ud60x18/Casting.sol\";\nimport { E, EXP_MAX_INPUT, PI, UNIT, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Exp_InputTooBig } from \"src/ud60x18/Errors.sol\";\nimport { exp } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Exp_Unit_Test is UD60x18_Unit_Test {\n    function test_Exp_Zero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 actual = exp(x);\n        UD60x18 expected = UNIT;\n        assertEq(actual, expected, \"UD60x18 exp\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_GtMaxPermitted() external whenNotZero {\n        UD60x18 x = EXP_MAX_INPUT + ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Exp_InputTooBig.selector, x));\n        exp(x);\n    }\n\n    modifier whenLteMaxPermitted() {\n        _;\n    }\n\n    function exp_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e18 }));\n        sets.push(set({ x: 0.000000000000001e18, expected: 1.000000000000000999e18 }));\n        sets.push(set({ x: 1e18, expected: 2_718281828459045234 }));\n        sets.push(set({ x: 2e18, expected: 7_389056098930650223 }));\n        sets.push(set({ x: E, expected: 15_154262241479264171 }));\n        sets.push(set({ x: 3e18, expected: 20_085536923187667724 }));\n        sets.push(set({ x: PI, expected: 23_140692632779268962 }));\n        sets.push(set({ x: 4e18, expected: 54_598150033144239019 }));\n        sets.push(set({ x: 11.89215e18, expected: 146115_107851442195738190 }));\n        sets.push(set({ x: 16e18, expected: 8886110_520507872601090007 }));\n        sets.push(set({ x: 20.82e18, expected: 1101567497_354306722521735975 }));\n        sets.push(set({ x: 33.333333e18, expected: 299559147061116_199277615819889397 }));\n        sets.push(set({ x: 64e18, expected: 6235149080811616783682415370_612321304359995711 }));\n        sets.push(set({ x: 71.002e18, expected: 6851360256686183998595702657852_843771046889809565 }));\n        sets.push(set({ x: 88.722839111672999627e18, expected: 340282366920938463222979506443879150094_819893272894857679 }));\n        sets.push(set({ x: EXP_MAX_INPUT, expected: 6277101735386680754977611748738314679353920434623901771623e18 }));\n        return sets;\n    }\n\n    function test_Exp() external parameterizedTest(exp_Sets()) whenNotZero whenLteMaxPermitted {\n        UD60x18 actual = exp(s.x);\n        assertEq(actual, s.expected, \"UD60x18 exp\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/exp/exp.tree",
    "content": "exp.t.sol\n├── when x is zero\n│  └── it should return the unit number\n└── when x is not zero\n   ├── when x is greater than the maximum permitted\n   │  └── it should revert\n   └── when x is less than or equal to the maximum permitted\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/exp2/exp2.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { ud } from \"src/ud60x18/Casting.sol\";\nimport { E, PI, UNIT, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Exp2_InputTooBig } from \"src/ud60x18/Errors.sol\";\nimport { exp2 } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Exp2_Unit_Test is UD60x18_Unit_Test {\n    UD60x18 internal constant MAX_PERMITTED = UD60x18.wrap(192e18 - 1);\n\n    function test_Exp2_Zero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 actual = exp2(x);\n        UD60x18 expected = UNIT;\n        assertEq(actual, expected, \"UD60x18 exp2\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_GtMaxPermitted() external whenNotZero {\n        UD60x18 x = MAX_PERMITTED + ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Exp2_InputTooBig.selector, x));\n        exp2(x);\n    }\n\n    modifier whenLteMaxPermitted() {\n        _;\n    }\n\n    function exp2_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e18 }));\n        sets.push(set({ x: 1e3, expected: 1_000000000000000693 }));\n        sets.push(set({ x: 0.3212e18, expected: 1_249369313012024883 }));\n        sets.push(set({ x: 1e18, expected: 2e18 }));\n        sets.push(set({ x: 2e18, expected: 4e18 }));\n        sets.push(set({ x: E, expected: 6_580885991017920969 }));\n        sets.push(set({ x: 3e18, expected: 8e18 }));\n        sets.push(set({ x: PI, expected: 8_824977827076287621 }));\n        sets.push(set({ x: 4e18, expected: 16e18 }));\n        sets.push(set({ x: 11.89215e18, expected: 3800_964933301542754377 }));\n        sets.push(set({ x: 16e18, expected: 65536e18 }));\n        sets.push(set({ x: 20.82e18, expected: 1851162_354076939434682641 }));\n        sets.push(set({ x: 33.333333e18, expected: 10822636909_120553492168423503 }));\n        sets.push(set({ x: 64e18, expected: 18_446744073709551616e18 }));\n        sets.push(set({ x: 71.002e18, expected: 2364458806372010440881_644926416580874919 }));\n        sets.push(set({ x: 88.7494e18, expected: 520273250104929479163928177_984511174562086061 }));\n        sets.push(set({ x: 95e18, expected: 39614081257_132168796771975168e18 }));\n        sets.push(set({ x: 127e18, expected: 170141183460469231731_687303715884105728e18 }));\n        sets.push(set({ x: 152.9065e18, expected: 10701459987152828635116598811554803403437267307_663014047009710338 }));\n        sets.push(set({ x: MAX_PERMITTED, expected: 6277101735386680759401282518710514696272033118492751795945e18 }));\n        return sets;\n    }\n\n    function test_Exp2() external parameterizedTest(exp2_Sets()) whenNotZero whenLteMaxPermitted {\n        UD60x18 actual = exp2(s.x);\n        assertEq(actual, s.expected, \"UD60x18 exp2\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/exp2/exp2.tree",
    "content": "exp2.t.sol\n├── when x is zero\n│  └── it should return the unit number\n└── when x is not zero\n   ├── when x is greater than or equal to 192\n   │  └── it should revert\n   └── when x is less than 192\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/floor/floor.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { MAX_UD60x18, MAX_WHOLE_UD60x18, PI, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { floor } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Floor_Unit_Test is UD60x18_Unit_Test {\n    function test_Floor_Zero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 actual = floor(x);\n        UD60x18 expected = ZERO;\n        assertEq(actual, expected, \"UD60x18 floor\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function floor_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: 0 }));\n        sets.push(set({ x: 0.5e18, expected: 0 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 1.125e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, expected: 2e18 }));\n        sets.push(set({ x: PI, expected: 3e18 }));\n        sets.push(set({ x: 4.2e18, expected: 4e18 }));\n        sets.push(set({ x: 1e24, expected: 1e24 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: MAX_WHOLE_UD60x18 }));\n        sets.push(set({ x: MAX_UD60x18, expected: MAX_WHOLE_UD60x18 }));\n        return sets;\n    }\n\n    function test_Floor_Positive() external parameterizedTest(floor_Sets()) whenNotZero {\n        UD60x18 actual = floor(s.x);\n        assertEq(actual, s.expected, \"UD60x18 floor\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/floor/floor.tree",
    "content": "floor.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/frac/frac.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { MAX_UD60x18, MAX_WHOLE_UD60x18, PI, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { frac } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Frac_Unit_Test is UD60x18_Unit_Test {\n    function test_Frac_Zero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 actual = frac(x);\n        UD60x18 expected = ZERO;\n        assertEq(actual, expected, \"UD60x18 frac\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function frac_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.1e18, expected: 0.1e18 }));\n        sets.push(set({ x: 0.5e18, expected: 0.5e18 }));\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 1.125e18, expected: 0.125e18 }));\n        sets.push(set({ x: 2e18, expected: 0 }));\n        sets.push(set({ x: PI, expected: 0.141592653589793238e18 }));\n        sets.push(set({ x: 4.2e18, expected: 0.2e18 }));\n        sets.push(set({ x: 1e24, expected: 0 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: 0 }));\n        sets.push(set({ x: MAX_UD60x18, expected: 0.584007913129639935e18 }));\n        return sets;\n    }\n\n    function test_Frac() external parameterizedTest(frac_Sets()) whenNotZero {\n        UD60x18 actual = frac(s.x);\n        assertEq(actual, s.expected, \"UD60x18 frac\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/frac/frac.tree",
    "content": "frac.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/gm/gm.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { E, MAX_UD60x18, MAX_WHOLE_UD60x18, PI } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Gm_Overflow } from \"src/ud60x18/Errors.sol\";\nimport { gm } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Gm_Unit_Test is UD60x18_Unit_Test {\n    // Biggest number whose non-fixed-point square fits in uint256\n    uint256 internal constant SQRT_MAX_UINT256 = 340282366920938463463374607431768211455;\n\n    function oneOperandZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: PI, expected: 0 }));\n        sets.push(set({ x: PI, y: 0, expected: 0 }));\n        return sets;\n    }\n\n    function test_Gm_OneOperandZero() external parameterizedTest(oneOperandZero_Sets()) {\n        UD60x18 actual = gm(s.x, s.y);\n        assertEq(actual, s.expected, \"UD60x18 gm\");\n    }\n\n    modifier whenOperandsNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_ProductOverflows() external whenOperandsNotZero {\n        UD60x18 x = SQRT_MAX_UD60x18 + ud(1);\n        UD60x18 y = SQRT_MAX_UD60x18 + ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Gm_Overflow.selector, x, y));\n        gm(x, y);\n    }\n\n    modifier whenProductDoesNotOverflow() {\n        _;\n    }\n\n    function gm_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 1e18, y: 4e18, expected: 2e18 }));\n        sets.push(set({ x: 2e18, y: 8e18, expected: 4e18 }));\n        sets.push(set({ x: E, y: 89.01e18, expected: 15_554879155787087514 }));\n        sets.push(set({ x: PI, y: 8.2e18, expected: 5_075535416036056441 }));\n        sets.push(set({ x: 322.47e18, y: 674.77e18, expected: 466_468736251423392217 }));\n        sets.push(set({ x: 2404.8e18, y: 7899.210662e18, expected: 4358_442588812843362311 }));\n        sets.push(set({ x: SQRT_MAX_UINT256, y: SQRT_MAX_UINT256, expected: SQRT_MAX_UINT256 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, y: 0.000000000000000001e18, expected: SQRT_MAX_UINT256 }));\n        sets.push(set({ x: MAX_UD60x18, y: 0.000000000000000001e18, expected: SQRT_MAX_UINT256 }));\n        return sets;\n    }\n\n    function test_Gm() external parameterizedTest(gm_Sets()) whenOperandsNotZero whenProductDoesNotOverflow {\n        UD60x18 actual = gm(s.x, s.y);\n        assertEq(actual, s.expected, \"UD60x18 gm\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/gm/gm.tree",
    "content": "gm.t.sol\n├── when one of the operands is zero\n│  └── it should return zero\n└── when neither operand is zero\n     ├── when the product of x and y overflows\n     │  └── it should revert\n     └── when the product of x and y does not overflow\n        └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/inv/inv.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { stdError } from \"forge-std/src/StdError.sol\";\n\nimport { MAX_UD60x18, MAX_WHOLE_UD60x18, PI, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { inv } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Inv_Unit_Test is UD60x18_Unit_Test {\n    function test_RevertWhen_Zero() external {\n        UD60x18 x = ZERO;\n        vm.expectRevert(stdError.divisionError);\n        inv(x);\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function inv_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 1e36 }));\n        sets.push(set({ x: 0.00001e18, expected: 100_000e18 }));\n        sets.push(set({ x: 0.05e18, expected: 20e18 }));\n        sets.push(set({ x: 0.1e18, expected: 10e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, expected: 0.5e18 }));\n        sets.push(set({ x: PI, expected: 0.318309886183790671e18 }));\n        sets.push(set({ x: 4e18, expected: 0.25e18 }));\n        sets.push(set({ x: 22e18, expected: 0.045454545454545454e18 }));\n        sets.push(set({ x: 100.135e18, expected: 0.00998651820042942e18 }));\n        sets.push(set({ x: 772.05e18, expected: 0.001295252898128359e18 }));\n        sets.push(set({ x: 2503e18, expected: 0.000399520575309628e18 }));\n        sets.push(set({ x: 1e36, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 1e36 + 1, expected: 0 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: 0 }));\n        sets.push(set({ x: MAX_UD60x18, expected: 0 }));\n        return sets;\n    }\n\n    function test_Inv() external parameterizedTest(inv_Sets()) whenNotZero {\n        UD60x18 actual = inv(s.x);\n        assertEq(actual, s.expected, \"UD60x18 inv\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/inv/inv.tree",
    "content": "inv.t.sol\n├── when x is zero\n│  └── it should revert\n└── when x is not zero\n   └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/ln/ln.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { ud } from \"src/ud60x18/Casting.sol\";\nimport { E, MAX_UD60x18, MAX_WHOLE_UD60x18, PI, UNIT } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Log_InputTooSmall } from \"src/ud60x18/Errors.sol\";\nimport { ln } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Ln_Unit_Test is UD60x18_Unit_Test {\n    function test_RevertWhen_LtUnit() external {\n        UD60x18 x = UNIT - ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Log_InputTooSmall.selector, x));\n        ln(x);\n    }\n\n    modifier whenGteUnit() {\n        _;\n    }\n\n    function ln_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 1.125e18, expected: 0.117783035656383442e18 }));\n        sets.push(set({ x: 2e18, expected: 0.693147180559945309e18 }));\n        sets.push(set({ x: E, expected: 0.99999999999999999e18 }));\n        sets.push(set({ x: PI, expected: 1_144729885849400163 }));\n        sets.push(set({ x: 4e18, expected: 1_386294361119890619 }));\n        sets.push(set({ x: 8e18, expected: 2_079441541679835928 }));\n        sets.push(set({ x: 1e24, expected: 13_815510557964274099 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: 135_999146549453176925 }));\n        sets.push(set({ x: MAX_UD60x18, expected: 135_999146549453176925 }));\n        return sets;\n    }\n\n    function test_Ln() external parameterizedTest(ln_Sets()) whenGteUnit {\n        UD60x18 actual = ln(s.x);\n        assertEq(actual, s.expected, \"UD60x18 ln\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/ln/ln.tree",
    "content": "inv.t.sol\n├── when x is less than the unit number\n│  └── it should revert\n└── when x is greater than or equal to the unit number\n   └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/log10/log10.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { E, MAX_UD60x18, MAX_WHOLE_UD60x18, PI, UNIT } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Log_InputTooSmall } from \"src/ud60x18/Errors.sol\";\nimport { log10 } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Log10_Unit_Test is UD60x18_Unit_Test {\n    function test_RevertWhen_LtUnit() external {\n        UD60x18 x = UNIT - ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Log_InputTooSmall.selector, x));\n        log10(x);\n    }\n\n    modifier whenGteUnit() {\n        _;\n    }\n\n    function powerOfTen_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 10e18, expected: 1e18 }));\n        sets.push(set({ x: 100e18, expected: 2e18 }));\n        sets.push(set({ x: 1e24, expected: 6e18 }));\n        sets.push(set({ x: 1e67, expected: 49e18 }));\n        sets.push(set({ x: 1e75, expected: 57e18 }));\n        sets.push(set({ x: 1e76, expected: 58e18 }));\n        return sets;\n    }\n\n    function test_Log10_PowerOfTen() external parameterizedTest(powerOfTen_Sets()) whenGteUnit {\n        UD60x18 actual = log10(s.x);\n        assertEq(actual, s.expected, \"UD60x18 log10\");\n    }\n\n    function notPowerOfTen_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1.00000000000001e18, expected: 0.000000000000004341e18 }));\n        sets.push(set({ x: E, expected: 0.434294481903251823e18 }));\n        sets.push(set({ x: PI, expected: 0.497149872694133849e18 }));\n        sets.push(set({ x: 4e18, expected: 0.60205999132796239e18 }));\n        sets.push(set({ x: 16e18, expected: 1_204119982655924781 }));\n        sets.push(set({ x: 32e18, expected: 1_505149978319905976 }));\n        sets.push(set({ x: 42.12e18, expected: 1_624488362513448905 }));\n        sets.push(set({ x: 1010.892143e18, expected: 3_004704821071980110 }));\n        sets.push(set({ x: 440934.1881e18, expected: 5_644373773418177966 }));\n        sets.push(set({ x: 1000000000000000000.000000000001e18, expected: 17_999999999999999999 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: 59_063678889979185987 }));\n        sets.push(set({ x: MAX_UD60x18, expected: 59_063678889979185987 }));\n        return sets;\n    }\n\n    function test_Log10_NotPowerOfTen() external parameterizedTest(notPowerOfTen_Sets()) whenGteUnit {\n        UD60x18 actual = log10(s.x);\n        assertEq(actual, s.expected, \"UD60x18 log10\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/log10/log10.tree",
    "content": "log10.t.sol\n├── when x is less than the unit number\n│  └── it should revert\n└── when x is greater than or equal to the unit number\n   ├── when x is a power of ten\n   │  └── it should return the correct value\n   └── when x is not a power of ten\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/log2/log2.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { ud } from \"src/ud60x18/Casting.sol\";\nimport { E, PI, MAX_UD60x18, MAX_WHOLE_UD60x18, UNIT } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Log_InputTooSmall } from \"src/ud60x18/Errors.sol\";\nimport { log2 } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Log2_Unit_Test is UD60x18_Unit_Test {\n    function test_RevertWhen_LtUnit() external {\n        UD60x18 x = UNIT - ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Log_InputTooSmall.selector, x));\n        log2(x);\n    }\n\n    modifier whenGteUnit() {\n        _;\n    }\n\n    function powerOfTwo_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1e18, expected: 0 }));\n        sets.push(set({ x: 2e18, expected: 1e18 }));\n        sets.push(set({ x: 4e18, expected: 2e18 }));\n        sets.push(set({ x: 8e18, expected: 3e18 }));\n        sets.push(set({ x: 16e18, expected: 4e18 }));\n        sets.push(set({ x: 2 ** 195 * 1e18, expected: 195e18 }));\n        return sets;\n    }\n\n    function test_Log2_PowerOfTwo() external parameterizedTest(powerOfTwo_Sets()) whenGteUnit {\n        UD60x18 actual = log2(s.x);\n        assertEq(actual, s.expected, \"UD60x18 log2\");\n    }\n\n    function notPowerOfTwo_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1.125e18, expected: 0.169925001442312346e18 }));\n        sets.push(set({ x: E, expected: 1_442695040888963394 }));\n        sets.push(set({ x: PI, expected: 1_651496129472318782 }));\n        sets.push(set({ x: 1e24, expected: 19_931568569324174075 }));\n        sets.push(set({ x: MAX_WHOLE_UD60x18, expected: 196_205294292027477728 }));\n        sets.push(set({ x: MAX_UD60x18, expected: 196_205294292027477728 }));\n        return sets;\n    }\n\n    function test_Log2_NotPowerOfTwo() external parameterizedTest(notPowerOfTwo_Sets()) whenGteUnit {\n        UD60x18 actual = log2(s.x);\n        assertEq(actual, s.expected, \"UD60x18 log2\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/log2/log2.tree",
    "content": "log2.t.sol\n├── when x is less than the unit number\n│  └── it should revert\n└── when x is greater than or equal to the unit number\n   ├── when x is a power of two\n   │  └── it should return the correct value\n   └── when x is not a power of two\n      └── it should return the correct value\n\n"
  },
  {
    "path": "test/unit/ud60x18/math/mul/mul.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { PRBMath_MulDiv18_Overflow } from \"src/Common.sol\";\nimport { E, MAX_UD60x18, MAX_WHOLE_UD60x18, PI } from \"src/ud60x18/Constants.sol\";\nimport { mul } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Mul_Unit_Test is UD60x18_Unit_Test {\n    function oneOperandZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: MAX_UD60x18, expected: 0 }));\n        sets.push(set({ x: MAX_UD60x18, y: 0, expected: 0 }));\n        return sets;\n    }\n\n    function test_Mul_OneOperandZero() external parameterizedTest(oneOperandZero_Sets()) {\n        assertEq(mul(s.x, s.y), s.expected, \"UD60x18 mul\");\n        assertEq(s.x * s.y, s.expected, \"UD60x18 *\");\n    }\n\n    modifier whenNeitherOperandZero() {\n        _;\n    }\n\n    function test_RevertWhen_ResultOverflowUD60x18_Function() external whenNeitherOperandZero {\n        UD60x18 x = SQRT_MAX_UD60x18 + ud(1);\n        UD60x18 y = SQRT_MAX_UD60x18 + ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_MulDiv18_Overflow.selector, x.unwrap(), y.unwrap()));\n        mul(x, y);\n    }\n\n    function test_RevertWhen_ResultOverflowUD60x18_Operator() external whenNeitherOperandZero {\n        UD60x18 x = SQRT_MAX_UD60x18 + ud(1);\n        UD60x18 y = SQRT_MAX_UD60x18 + ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_MulDiv18_Overflow.selector, x.unwrap(), y.unwrap()));\n        x * y;\n    }\n\n    modifier whenResultDoesNotOverflowUD60x18() {\n        _;\n    }\n\n    function mul_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0 }));\n        sets.push(set({ x: 0.000000000000000006e18, y: 0.1e18, expected: 0 }));\n        sets.push(set({ x: 0.000000001e18, y: 0.000000001e18, expected: 0.000000000000000001e18 }));\n        sets.push(set({ x: 0.00001e18, y: 0.00001e18, expected: 0.0000000001e18 }));\n        sets.push(set({ x: 0.001e18, y: 0.01e18, expected: 0.00001e18 }));\n        sets.push(set({ x: 0.01e18, y: 0.05e18, expected: 0.0005e18 }));\n        sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 2.098e18, y: 1.119e18, expected: 2.347662e18 }));\n        sets.push(set({ x: PI, y: E, expected: 8_539734222673567063 }));\n        sets.push(set({ x: 18.3e18, y: 12.04e18, expected: 220.332e18 }));\n        sets.push(set({ x: 314.271e18, y: 188.19e18, expected: 59_142.65949e18 }));\n        sets.push(set({ x: 9_817e18, y: 2_348e18, expected: 23_050_316e18 }));\n        sets.push(set({ x: 12_983.989e18, y: 782.99e18, expected: 1_016_6333.54711e18 }));\n        sets.push(set({ x: 1e24, y: 1e20, expected: 1e26 }));\n        sets.push(\n            set({\n                x: SQRT_MAX_UD60x18,\n                y: SQRT_MAX_UD60x18,\n                expected: 115792089237316195423570985008687907853269984664959999305615_707080986380425072\n            })\n        );\n        sets.push(set({ x: MAX_WHOLE_UD60x18, y: 0.000000000000000001e18, expected: MAX_SCALED_UD60x18 }));\n        sets.push(set({ x: MAX_UD60x18 - ud(0.5e18), y: 0.000000000000000001e18, expected: MAX_SCALED_UD60x18 }));\n        return sets;\n    }\n\n    function test_Mul() external parameterizedTest(mul_Sets()) whenNeitherOperandZero whenResultDoesNotOverflowUD60x18 {\n        assertEq(mul(s.x, s.y), s.expected, \"UD60x18 mul\");\n        assertEq(s.x * s.y, s.expected, \"UD60x18 *\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/mul/mul.tree",
    "content": "div.t.sol\n├── when one of the operands is zero\n│  └── it should return zero\n└── when neither operand is zero\n   ├── when the result overflows ud60x18\n   │  └── it should revert\n   └── when the result does not overflow ud60x18\n      └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/pow/pow.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { E, PI, UNIT, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { pow } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Pow_Unit_Test is UD60x18_Unit_Test {\n    function test_Pow_BaseZero_ExponentZero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 y = ZERO;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = UNIT;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    function test_Pow_BaseZero_ExponentNotZero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 y = PI;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = ZERO;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    modifier whenBaseNotZero() {\n        _;\n    }\n\n    function test_Pow_BaseUnit() external pure whenBaseNotZero {\n        UD60x18 x = UNIT;\n        UD60x18 y = PI;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = UNIT;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    modifier whenBaseNotUnit() {\n        _;\n    }\n\n    function test_Pow_ExponentZero() external pure whenBaseNotZero whenBaseNotUnit {\n        UD60x18 x = PI;\n        UD60x18 y = ZERO;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = UNIT;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    modifier whenExponentNotZero() {\n        _;\n    }\n\n    function test_Pow_ExponentUnit() external pure whenBaseNotZero whenBaseNotUnit whenExponentNotZero {\n        UD60x18 x = PI;\n        UD60x18 y = UNIT;\n        UD60x18 actual = pow(x, y);\n        UD60x18 expected = x;\n        assertEq(actual, expected, \"UD60x18 pow\");\n    }\n\n    modifier whenExponentNotUnit() {\n        _;\n    }\n\n    function baseGtUnit_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1e18 + 1, y: 2e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, y: 1.5e18, expected: 2_828427124746190097 }));\n        sets.push(set({ x: E, y: 1.66976e18, expected: 5_310893029888037560 }));\n        sets.push(set({ x: E, y: E, expected: 15_154262241479263793 }));\n        sets.push(set({ x: PI, y: PI, expected: 36_462159607207910473 }));\n        sets.push(set({ x: 11e18, y: 28.5e18, expected: 478290249106383504389245497918_050372801213485439 }));\n        sets.push(set({ x: 32.15e18, y: 23.99e18, expected: 1436387590627448555101723413293079116_943375472179194989 }));\n        sets.push(set({ x: 406e18, y: 0.25e18, expected: 4_488812947719016318 }));\n        sets.push(set({ x: 1729e18, y: 0.98e18, expected: 1489_495149922256917866 }));\n        sets.push(set({ x: 33441e18, y: 2.1891e18, expected: 8018621589_681923269491820156 }));\n        sets.push(\n            set({\n                x: 340282366920938463463374607431768211455e18,\n                y: 1e18 + 1,\n                expected: 340282366920938487757736552507248225013_000000000004316573\n            })\n        );\n        sets.push(\n            set({ x: 2 ** 192 * 1e18 - 1, y: 1e18 - 1, expected: 6277101735386679823624773486129835356722228023657461399187e18 })\n        );\n        return sets;\n    }\n\n    function test_Pow_BaseGtUnit()\n        external\n        parameterizedTest(baseGtUnit_Sets())\n        whenBaseNotZero\n        whenBaseNotUnit\n        whenExponentNotZero\n        whenExponentNotUnit\n    {\n        UD60x18 actual = pow(s.x, s.y);\n        assertEq(actual, s.expected);\n    }\n\n    function baseLtUnit_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, y: 1.78e18, expected: 0 }));\n        sets.push(set({ x: 0.01e18, y: E, expected: 0.000003659622955309e18 }));\n        sets.push(set({ x: 0.125e18, y: PI, expected: 0.001454987061394186e18 }));\n        sets.push(set({ x: 0.25e18, y: 3e18, expected: 0.015625e18 }));\n        sets.push(set({ x: 0.45e18, y: 2.2e18, expected: 0.172610627076774731e18 }));\n        sets.push(set({ x: 0.5e18, y: 0.481e18, expected: 0.716480825186549911e18 }));\n        sets.push(set({ x: 0.6e18, y: 0.95e18, expected: 0.615522152723696171e18 }));\n        sets.push(set({ x: 0.7e18, y: 3.1e18, expected: 0.330981655626097448e18 }));\n        sets.push(set({ x: 0.75e18, y: 4e18, expected: 0.316406250000000008e18 }));\n        sets.push(set({ x: 0.8e18, y: 5e18, expected: 0.327680000000000015e18 }));\n        sets.push(set({ x: 0.9e18, y: 2.5e18, expected: 0.768433471420916194e18 }));\n        sets.push(set({ x: 1e18 - 1, y: 0.08e18, expected: 1e18 }));\n        return sets;\n    }\n\n    function test_Pow_BaseLtUnit()\n        external\n        parameterizedTest(baseLtUnit_Sets())\n        whenBaseNotZero\n        whenBaseNotUnit\n        whenExponentNotZero\n        whenExponentNotUnit\n    {\n        UD60x18 actual = pow(s.x, s.y);\n        assertEq(actual, s.expected);\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/pow/pow.tree",
    "content": "pow.t.sol\n├── when the base is zero\n│  ├── when the exponent is zero\n│  │  └── it should return the unit number\n│  └── when the exponent is not zero\n│     └── it should return zero\n└── when the base is not zero\n   ├── when the base is the unit number\n   │  └── it should return the unit number\n   └── when the base is not the unit number\n      ├── when the exponent is zero\n      │  └── it should return the base\n      └── when the exponent is not zero\n         ├── when the exponent is the unit number\n         │  └── it should return the base\n         └── when the exponent is not the unit number\n            ├── when the base is greater than the maximum permitted\n            │  └── it should revert\n            └── when the base is less than or equal to the maximum permitted\n               ├── when the base is greater than the unit number\n               │  └── it should use the standard formula and return the correct value\n               └── when the base is less than the unit number\n                  └── it should use the equivalent formula and return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/powu/powu.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { ud } from \"src/ud60x18/Casting.sol\";\nimport { PRBMath_MulDiv18_Overflow } from \"src/Common.sol\";\nimport { E, MAX_UD60x18, MAX_WHOLE_UD60x18, PI, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { powu } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Powu_Unit_Test is UD60x18_Unit_Test {\n    function test_Powu_BaseAndExponentZero() external pure {\n        UD60x18 x = ZERO;\n        uint256 y = 0;\n        UD60x18 actual = powu(x, y);\n        UD60x18 expected = ud(1e18);\n        assertEq(actual, expected, \"UD60x18 powu\");\n    }\n\n    function baseZeroExponentNotZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0, y: 1, expected: 0 }));\n        sets.push(set({ x: 0, y: 2, expected: 0 }));\n        sets.push(set({ x: 0, y: 3, expected: 0 }));\n        return sets;\n    }\n\n    function test_Powu_BaseZeroExponentNotZero() external parameterizedTest(baseZeroExponentNotZero_Sets()) {\n        UD60x18 actual = powu(s.x, s.y.unwrap());\n        assertEq(actual, s.expected, \"UD60x18 powu\");\n    }\n\n    modifier whenBaseNotZero() {\n        _;\n    }\n\n    function exponentZero_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: PI, expected: 1e18 }));\n        sets.push(set({ x: MAX_UD60x18 - ud(1), expected: 1e18 }));\n        return sets;\n    }\n\n    function test_Powu_ExponentZero() external parameterizedTest(exponentZero_Sets()) whenBaseNotZero {\n        UD60x18 actual = powu(s.x, s.y.unwrap());\n        assertEq(actual, s.expected, \"UD60x18 powu\");\n    }\n\n    modifier whenExponentNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_ResultOverflowsUD60x18() external whenBaseNotZero whenExponentNotZero {\n        UD60x18 x = MAX_WHOLE_UD60x18;\n        uint256 y = 2;\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_MulDiv18_Overflow.selector, x.unwrap(), x.unwrap()));\n        powu(x, y);\n    }\n\n    modifier whenResultDoesNotOverflowUD60x18() {\n        _;\n    }\n\n    function powu_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.001e18, y: 3, expected: 1e9 }));\n        sets.push(set({ x: 0.1e18, y: 2, expected: 1e16 }));\n        sets.push(set({ x: 1e18, y: 1, expected: 1e18 }));\n        sets.push(set({ x: 2e18, y: 5, expected: 32e18 }));\n        sets.push(set({ x: 2e18, y: 100, expected: 1267650600228_229401496703205376e18 }));\n        sets.push(set({ x: E, y: 2, expected: 7_389056098930650225 }));\n        sets.push(set({ x: PI, y: 3, expected: 31_006276680299820158 }));\n        sets.push(set({ x: 5.491e18, y: 19, expected: 113077820843204_476043049664958463 }));\n        sets.push(set({ x: 100e18, y: 4, expected: 1e26 }));\n        sets.push(set({ x: 478.77e18, y: 20, expected: 400441047687151121501368529571950234763284476825512183793320584974037932 }));\n        sets.push(set({ x: 6452.166e18, y: 7, expected: 4655204093726194074224341678_62736844121311696 }));\n        sets.push(set({ x: 1e24, y: 3, expected: 1e36 }));\n        sets.push(\n            set({\n                x: 38685626227668133590.597631999999999999e18,\n                y: 3,\n                expected: 57896044618658097711785492504343953922145259302939748254975_940481744194640509\n            })\n        );\n        sets.push(\n            set({\n                x: SQRT_MAX_UD60x18, y: 2, expected: 115792089237316195423570985008687907853269984664959999305615_707080986380425072\n            })\n        );\n        sets.push(set({ x: MAX_WHOLE_UD60x18, y: 1, expected: MAX_WHOLE_UD60x18 }));\n        sets.push(set({ x: MAX_UD60x18, y: 1, expected: MAX_UD60x18 }));\n        return sets;\n    }\n\n    function test_Powu()\n        external\n        parameterizedTest(powu_Sets())\n        whenBaseNotZero\n        whenExponentNotZero\n        whenResultDoesNotOverflowUD60x18\n    {\n        UD60x18 actual = powu(s.x, s.y.unwrap());\n        assertEq(actual, s.expected, \"UD60x18 powu\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/powu/powu.tree",
    "content": "powu.t.sol\n├── when the base is zero\n│  ├── when the exponent is zero\n│  │  └── it should return the unit number\n│  └── when the exponent is not zero\n│  │  └── it should return zero\n└── when the base is not zero\n   ├── when the exponent is zero\n   │  └── it should return the unit number\n   └── when the exponent is not zero\n      ├── when the result overflows ud60x18\n      │  └── it should revert\n      └── when the result does not overflow ud60x18\n         └── it should return the correct value\n"
  },
  {
    "path": "test/unit/ud60x18/math/sqrt/sqrt.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19 <0.9.0;\n\nimport { E, PI, ZERO } from \"src/ud60x18/Constants.sol\";\nimport { PRBMath_UD60x18_Sqrt_Overflow } from \"src/ud60x18/Errors.sol\";\nimport { sqrt } from \"src/ud60x18/Math.sol\";\nimport { UD60x18 } from \"src/ud60x18/ValueType.sol\";\n\nimport { UD60x18_Unit_Test } from \"../../UD60x18.t.sol\";\n\ncontract Sqrt_Unit_Test is UD60x18_Unit_Test {\n    UD60x18 internal constant MAX_PERMITTED = UD60x18.wrap(115792089237316195423570985008687907853269_984665640564039457);\n\n    function test_Sqrt_Zero() external pure {\n        UD60x18 x = ZERO;\n        UD60x18 actual = sqrt(x);\n        UD60x18 expected = ZERO;\n        assertEq(actual, expected, \"UD60x18 sqrt\");\n    }\n\n    modifier whenNotZero() {\n        _;\n    }\n\n    function test_RevertWhen_GtMaxPermitted() external whenNotZero {\n        UD60x18 x = MAX_PERMITTED + ud(1);\n        vm.expectRevert(abi.encodeWithSelector(PRBMath_UD60x18_Sqrt_Overflow.selector, x));\n        sqrt(x);\n    }\n\n    modifier whenLteMaxPermitted() {\n        _;\n    }\n\n    function sqrt_Sets() internal returns (Set[] memory) {\n        delete sets;\n        sets.push(set({ x: 0.000000000000000001e18, expected: 0.000000001e18 }));\n        sets.push(set({ x: 0.000000000000001e18, expected: 0.000000031622776601e18 }));\n        sets.push(set({ x: 1e18, expected: 1e18 }));\n        sets.push(set({ x: 2e18, expected: 1_414213562373095048 }));\n        sets.push(set({ x: E, expected: 1_648721270700128146 }));\n        sets.push(set({ x: 3e18, expected: 1_732050807568877293 }));\n        sets.push(set({ x: PI, expected: 1_772453850905516027 }));\n        sets.push(set({ x: 4e18, expected: 2e18 }));\n        sets.push(set({ x: 16e18, expected: 4e18 }));\n        sets.push(set({ x: 1e35, expected: 316227766_016837933199889354 }));\n        sets.push(set({ x: 12489131238983290393813_123784889921092801, expected: 111754781727_598977910452220959 }));\n        sets.push(set({ x: 1889920002192904839344128288891377_732371920009212883, expected: 43473210166640613973238162807779776 }));\n        sets.push(set({ x: 1e58, expected: 1e38 }));\n        sets.push(set({ x: 5e58, expected: 223606797749978969640_917366873127623544 }));\n        sets.push(set({ x: MAX_PERMITTED, expected: 340282366920938463463_374607431768211455 }));\n        return sets;\n    }\n\n    function test_Sqrt() external parameterizedTest(sqrt_Sets()) whenNotZero whenLteMaxPermitted {\n        UD60x18 actual = sqrt(s.x);\n        assertEq(actual, s.expected, \"UD60x18 sqrt\");\n    }\n}\n"
  },
  {
    "path": "test/unit/ud60x18/math/sqrt/sqrt.tree",
    "content": "sqrt.t.sol\n├── when x is zero\n│  └── it should return zero\n└── when x is not zero\n   ├── when x is greater than the maximum permitted\n   │  └── it should revert\n   └── when x is less than or equal to the maximum permitted\n      └── it should return the correct value\n"
  },
  {
    "path": "test/utils/Assertions.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\nimport { StdAssertions } from \"forge-std/src/StdAssertions.sol\";\n\nimport { SD1x18 } from \"../../src/sd1x18/ValueType.sol\";\nimport { SD21x18 } from \"../../src/sd21x18/ValueType.sol\";\nimport { SD59x18 } from \"../../src/sd59x18/ValueType.sol\";\nimport { UD2x18 } from \"../../src/ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"../../src/ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"../../src/ud60x18/ValueType.sol\";\n\ncontract PRBMathAssertions is StdAssertions {\n    /*//////////////////////////////////////////////////////////////////////////\n                                       SD1X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function assertEq(SD1x18 a, SD1x18 b) internal pure {\n        assertEq(SD1x18.unwrap(a), SD1x18.unwrap(b));\n    }\n\n    function assertEq(SD1x18 a, SD1x18 b, string memory err) internal pure {\n        assertEq(SD1x18.unwrap(a), SD1x18.unwrap(b), err);\n    }\n\n    function assertEq(SD1x18 a, int64 b) internal pure {\n        assertEq(SD1x18.unwrap(a), b);\n    }\n\n    function assertEq(SD1x18 a, int64 b, string memory err) internal pure {\n        assertEq(SD1x18.unwrap(a), b, err);\n    }\n\n    function assertEq(int64 a, SD1x18 b) internal pure {\n        assertEq(a, SD1x18.unwrap(b));\n    }\n\n    function assertEq(int64 a, SD1x18 b, string memory err) internal pure {\n        assertEq(a, SD1x18.unwrap(b), err);\n    }\n\n    function assertEq(SD1x18[] memory a, SD1x18[] memory b) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(SD1x18[] memory a, SD1x18[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(SD1x18[] memory a, int64[] memory b) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(SD1x18[] memory a, int64[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(int64[] memory a, SD1x18[] memory b) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(int64[] memory a, SD1x18[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                       SD21X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function assertEq(SD21x18 a, SD21x18 b) internal pure {\n        assertEq(SD21x18.unwrap(a), SD21x18.unwrap(b));\n    }\n\n    function assertEq(SD21x18 a, SD21x18 b, string memory err) internal pure {\n        assertEq(SD21x18.unwrap(a), SD21x18.unwrap(b), err);\n    }\n\n    function assertEq(SD21x18 a, int64 b) internal pure {\n        assertEq(SD21x18.unwrap(a), b);\n    }\n\n    function assertEq(SD21x18 a, int64 b, string memory err) internal pure {\n        assertEq(SD21x18.unwrap(a), b, err);\n    }\n\n    function assertEq(int64 a, SD21x18 b) internal pure {\n        assertEq(a, SD21x18.unwrap(b));\n    }\n\n    function assertEq(int64 a, SD21x18 b, string memory err) internal pure {\n        assertEq(a, SD21x18.unwrap(b), err);\n    }\n\n    function assertEq(SD21x18[] memory a, SD21x18[] memory b) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(SD21x18[] memory a, SD21x18[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(SD21x18[] memory a, int64[] memory b) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(SD21x18[] memory a, int64[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(int64[] memory a, SD21x18[] memory b) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(int64[] memory a, SD21x18[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                       SD59X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function assertEq(SD59x18 a, SD59x18 b) internal pure {\n        assertEq(SD59x18.unwrap(a), SD59x18.unwrap(b));\n    }\n\n    function assertEq(SD59x18 a, SD59x18 b, string memory err) internal pure {\n        assertEq(SD59x18.unwrap(a), SD59x18.unwrap(b), err);\n    }\n\n    function assertEq(SD59x18 a, int256 b) internal pure {\n        assertEq(SD59x18.unwrap(a), b);\n    }\n\n    function assertEq(SD59x18 a, int256 b, string memory err) internal pure {\n        assertEq(SD59x18.unwrap(a), b, err);\n    }\n\n    function assertEq(int256 a, SD59x18 b) internal pure {\n        assertEq(a, SD59x18.unwrap(b));\n    }\n\n    function assertEq(int256 a, SD59x18 b, string memory err) internal pure {\n        assertEq(a, SD59x18.unwrap(b), err);\n    }\n\n    function assertEq(SD59x18[] memory a, SD59x18[] memory b) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(SD59x18[] memory a, SD59x18[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        int256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(SD59x18[] memory a, int256[] memory b) internal pure {\n        int256[] memory castedA;\n        assembly {\n            castedA := a\n        }\n        assertEq(castedA, b);\n    }\n\n    function assertEq(SD59x18[] memory a, int256[] memory b, string memory err) internal pure {\n        int256[] memory castedA;\n        assembly {\n            castedA := a\n        }\n        assertEq(castedA, b, err);\n    }\n\n    function assertEq(int256[] memory a, SD59x18[] memory b) internal pure {\n        int256[] memory castedB;\n        assembly {\n            castedB := b\n        }\n        assertEq(a, b);\n    }\n\n    function assertEq(int256[] memory a, SD59x18[] memory b, string memory err) internal pure {\n        int256[] memory castedB;\n        assembly {\n            castedB := b\n        }\n        assertEq(a, b, err);\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                       UD2X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function assertEq(UD2x18 a, UD2x18 b) internal pure {\n        assertEq(UD2x18.unwrap(a), UD2x18.unwrap(b));\n    }\n\n    function assertEq(UD2x18 a, UD2x18 b, string memory err) internal pure {\n        assertEq(UD2x18.unwrap(a), UD2x18.unwrap(b), err);\n    }\n\n    function assertEq(UD2x18 a, uint64 b) internal pure {\n        assertEq(UD2x18.unwrap(a), uint256(b));\n    }\n\n    function assertEq(UD2x18 a, uint64 b, string memory err) internal pure {\n        assertEq(UD2x18.unwrap(a), uint256(b), err);\n    }\n\n    function assertEq(uint64 a, UD2x18 b) internal pure {\n        assertEq(uint256(a), UD2x18.unwrap(b));\n    }\n\n    function assertEq(uint64 a, UD2x18 b, string memory err) internal pure {\n        assertEq(uint256(a), UD2x18.unwrap(b), err);\n    }\n\n    function assertEq(UD2x18[] memory a, UD2x18[] memory b) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(UD2x18[] memory a, UD2x18[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(UD2x18[] memory a, uint64[] memory b) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(UD2x18[] memory a, uint64[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(uint64[] memory a, UD2x18[] memory b) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(uint64[] memory a, UD2x18[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                       UD21X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function assertEq(UD21x18 a, UD21x18 b) internal pure {\n        assertEq(UD21x18.unwrap(a), UD21x18.unwrap(b));\n    }\n\n    function assertEq(UD21x18 a, UD21x18 b, string memory err) internal pure {\n        assertEq(UD21x18.unwrap(a), UD21x18.unwrap(b), err);\n    }\n\n    function assertEq(UD21x18 a, uint128 b) internal pure {\n        assertEq(UD21x18.unwrap(a), uint256(b));\n    }\n\n    function assertEq(UD21x18 a, uint128 b, string memory err) internal pure {\n        assertEq(UD21x18.unwrap(a), uint256(b), err);\n    }\n\n    function assertEq(uint128 a, UD21x18 b) internal pure {\n        assertEq(uint256(a), UD21x18.unwrap(b));\n    }\n\n    function assertEq(uint128 a, UD21x18 b, string memory err) internal pure {\n        assertEq(uint256(a), UD21x18.unwrap(b), err);\n    }\n\n    function assertEq(UD21x18[] memory a, UD21x18[] memory b) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(UD21x18[] memory a, UD21x18[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(UD21x18[] memory a, uint128[] memory b) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(UD21x18[] memory a, uint128[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(uint128[] memory a, UD21x18[] memory b) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(uint128[] memory a, UD21x18[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                       UD60X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    function assertEq(UD60x18 a, UD60x18 b) internal pure {\n        assertEq(UD60x18.unwrap(a), UD60x18.unwrap(b));\n    }\n\n    function assertEq(UD60x18 a, UD60x18 b, string memory err) internal pure {\n        assertEq(UD60x18.unwrap(a), UD60x18.unwrap(b), err);\n    }\n\n    function assertEq(UD60x18 a, uint256 b) internal pure {\n        assertEq(UD60x18.unwrap(a), b);\n    }\n\n    function assertEq(UD60x18 a, uint256 b, string memory err) internal pure {\n        assertEq(UD60x18.unwrap(a), b, err);\n    }\n\n    function assertEq(uint256 a, UD60x18 b) internal pure {\n        assertEq(a, UD60x18.unwrap(b));\n    }\n\n    function assertEq(uint256 a, UD60x18 b, string memory err) internal pure {\n        assertEq(a, UD60x18.unwrap(b), err);\n    }\n\n    function assertEq(UD60x18[] memory a, UD60x18[] memory b) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB);\n    }\n\n    function assertEq(UD60x18[] memory a, UD60x18[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        uint256[] memory castedB;\n        assembly {\n            castedA := a\n            castedB := b\n        }\n        assertEq(castedA, castedB, err);\n    }\n\n    function assertEq(UD60x18[] memory a, uint256[] memory b) internal pure {\n        uint256[] memory castedA;\n        assembly {\n            castedA := a\n        }\n        assertEq(castedA, b);\n    }\n\n    function assertEq(UD60x18[] memory a, uint256[] memory b, string memory err) internal pure {\n        uint256[] memory castedA;\n        assembly {\n            castedA := a\n        }\n        assertEq(castedA, b, err);\n    }\n\n    function assertEq(uint256[] memory a, SD59x18[] memory b) internal pure {\n        uint256[] memory castedB;\n        assembly {\n            castedB := b\n        }\n        assertEq(a, b);\n    }\n\n    function assertEq(uint256[] memory a, SD59x18[] memory b, string memory err) internal pure {\n        uint256[] memory castedB;\n        assembly {\n            castedB := b\n        }\n        assertEq(a, b, err);\n    }\n}\n"
  },
  {
    "path": "test/utils/Utils.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\nimport { StdUtils } from \"forge-std/src/StdUtils.sol\";\n\nimport { SD1x18 } from \"../../src/sd1x18/ValueType.sol\";\nimport { SD21x18 } from \"../../src/sd21x18/ValueType.sol\";\nimport { SD59x18 } from \"../../src/sd59x18/ValueType.sol\";\nimport { UD2x18 } from \"../../src/ud2x18/ValueType.sol\";\nimport { UD21x18 } from \"../../src/ud21x18/ValueType.sol\";\nimport { UD60x18 } from \"../../src/ud60x18/ValueType.sol\";\n\ncontract PRBMathUtils is StdUtils {\n    /*//////////////////////////////////////////////////////////////////////////\n                                      SD1x18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @dev Helper function to bound an SD1x18 number, which console logs the result.\n    function bound(SD1x18 x, SD1x18 min, SD1x18 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(bound(int256(x.unwrap()), int256(min.unwrap()), int256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound an SD1x18 number, which does NOT console log the result.\n    function _bound(SD1x18 x, SD1x18 min, SD1x18 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(_bound(int256(x.unwrap()), int256(min.unwrap()), int256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound an SD1x18 number, which console logs the result.\n    function bound(SD1x18 x, int64 min, SD1x18 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(bound(int256(x.unwrap()), int256(min), int256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound an SD1x18 number, which does NOT console log the result.\n    function _bound(SD1x18 x, int64 min, SD1x18 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(_bound(int256(x.unwrap()), int256(min), int256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound an SD1x18 number, which console logs the result.\n    function bound(SD1x18 x, SD1x18 min, int64 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(bound(int256(x.unwrap()), int256(min.unwrap()), int256(max))));\n    }\n\n    /// @dev Helper function to bound an SD1x18 number, which does NOT console log the result.\n    function _bound(SD1x18 x, SD1x18 min, int64 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(_bound(int256(x.unwrap()), int256(min.unwrap()), int256(max))));\n    }\n\n    /// @dev Helper function to bound an SD1x18 number, which console logs the result.\n    function bound(SD1x18 x, int64 min, int64 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(bound(int256(x.unwrap()), int256(min), int256(max))));\n    }\n\n    /// @dev Helper function to bound an SD1x18 number, which does NOT console log the result.\n    function _bound(SD1x18 x, int64 min, int64 max) internal pure returns (SD1x18) {\n        return SD1x18.wrap(int64(_bound(int256(x.unwrap()), int256(min), int256(max))));\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                      SD21x18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @dev Helper function to bound an SD21x18 number, which console logs the result.\n    function bound(SD21x18 x, SD21x18 min, SD21x18 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(bound(int256(x.unwrap()), int256(min.unwrap()), int256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound an SD21x18 number, which does NOT console log the result.\n    function _bound(SD21x18 x, SD21x18 min, SD21x18 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(_bound(x.unwrap(), int256(min.unwrap()), int256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound an SD21x18 number, which console logs the result.\n    function bound(SD21x18 x, int128 min, SD21x18 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(bound(int256(x.unwrap()), int256(min), int256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound an SD21x18 number, which does NOT console log the result.\n    function _bound(SD21x18 x, int128 min, SD21x18 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(_bound(x.unwrap(), min, max.unwrap())));\n    }\n\n    /// @dev Helper function to bound an SD21x18 number, which console logs the result.\n    function bound(SD21x18 x, SD21x18 min, int128 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(bound(int256(x.unwrap()), int256(min.unwrap()), int256(max))));\n    }\n\n    /// @dev Helper function to bound an SD21x18 number, which does NOT console log the result.\n    function _bound(SD21x18 x, SD21x18 min, int128 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(_bound(int256(x.unwrap()), int256(min.unwrap()), int256(max))));\n    }\n\n    /// @dev Helper function to bound an SD21x18 number, which console logs the result.\n    function bound(SD21x18 x, int128 min, int128 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(bound(int256(x.unwrap()), int256(min), int256(max))));\n    }\n\n    /// @dev Helper function to bound an SD21x18 number, which does NOT console log the result.\n    function _bound(SD21x18 x, int128 min, int128 max) internal pure returns (SD21x18) {\n        return SD21x18.wrap(int128(_bound(int256(x.unwrap()), int256(min), int256(max))));\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                      SD59X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @dev Helper function to bound an SD59x18 number, which console logs the result.\n    function bound(SD59x18 x, SD59x18 min, SD59x18 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(bound(x.unwrap(), min.unwrap(), max.unwrap()));\n    }\n\n    /// @dev Helper function to bound an SD59x18 number, which does NOT console log the result.\n    function _bound(SD59x18 x, SD59x18 min, SD59x18 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(_bound(x.unwrap(), min.unwrap(), max.unwrap()));\n    }\n\n    /// @dev Helper function to bound an SD59x18 number, which console logs the result.\n    function bound(SD59x18 x, int256 min, SD59x18 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(bound(x.unwrap(), min, max.unwrap()));\n    }\n\n    /// @dev Helper function to bound an SD59x18 number, which does NOT console log the result.\n    function _bound(SD59x18 x, int256 min, SD59x18 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(_bound(x.unwrap(), min, max.unwrap()));\n    }\n\n    /// @dev Helper function to bound an SD59x18 number, which console logs the result.\n    function bound(SD59x18 x, SD59x18 min, int256 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(bound(x.unwrap(), min.unwrap(), max));\n    }\n\n    /// @dev Helper function to bound an SD59x18 number, which does NOT console log the result.\n    function _bound(SD59x18 x, SD59x18 min, int256 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(_bound(x.unwrap(), min.unwrap(), max));\n    }\n\n    /// @dev Helper function to bound an SD59x18 number, which console logs the result.\n    function bound(SD59x18 x, int256 min, int256 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(bound(x.unwrap(), min, max));\n    }\n\n    /// @dev Helper function to bound an SD59x18 number, which does NOT console log the result.\n    function _bound(SD59x18 x, int256 min, int256 max) internal pure returns (SD59x18) {\n        return SD59x18.wrap(_bound(x.unwrap(), min, max));\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                      UD2x18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @dev Helper function to bound a UD2x18 number, which console logs the result.\n    function bound(UD2x18 x, UD2x18 min, UD2x18 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD2x18 number, which does NOT console log the result.\n    function _bound(UD2x18 x, UD2x18 min, UD2x18 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(_bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD2x18 number, which console logs the result.\n    function bound(UD2x18 x, uint64 min, UD2x18 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(bound(uint256(x.unwrap()), uint256(min), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD2x18 number, which does NOT console log the result.\n    function _bound(UD2x18 x, uint64 min, UD2x18 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(_bound(uint256(x.unwrap()), uint256(min), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD2x18 number, which console logs the result.\n    function bound(UD2x18 x, UD2x18 min, uint64 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max))));\n    }\n\n    /// @dev Helper function to bound a UD2x18 number, which does NOT console log the result.\n    function _bound(UD2x18 x, UD2x18 min, uint64 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(_bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max))));\n    }\n\n    /// @dev Helper function to bound a UD2x18 number, which console logs the result.\n    function bound(UD2x18 x, uint64 min, uint64 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(bound(uint256(x.unwrap()), uint256(min), uint256(max))));\n    }\n\n    /// @dev Helper function to bound a UD2x18 number, which does NOT console log the result.\n    function _bound(UD2x18 x, uint64 min, uint64 max) internal pure returns (UD2x18) {\n        return UD2x18.wrap(uint64(_bound(uint256(x.unwrap()), uint256(min), uint256(max))));\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                      UD21x18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @dev Helper function to bound a UD21x18 number, which console logs the result.\n    function bound(UD21x18 x, UD21x18 min, UD21x18 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD21x18 number, which does NOT console log the result.\n    function _bound(UD21x18 x, UD21x18 min, UD21x18 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(_bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD21x18 number, which console logs the result.\n    function bound(UD21x18 x, uint128 min, UD21x18 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(bound(uint256(x.unwrap()), uint256(min), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD21x18 number, which does NOT console log the result.\n    function _bound(UD21x18 x, uint128 min, UD21x18 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(_bound(uint256(x.unwrap()), uint256(min), uint256(max.unwrap()))));\n    }\n\n    /// @dev Helper function to bound a UD21x18 number, which console logs the result.\n    function bound(UD21x18 x, UD21x18 min, uint128 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max))));\n    }\n\n    /// @dev Helper function to bound a UD21x18 number, which does NOT console log the result.\n    function _bound(UD21x18 x, UD21x18 min, uint128 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(_bound(uint256(x.unwrap()), uint256(min.unwrap()), uint256(max))));\n    }\n\n    /// @dev Helper function to bound a UD21x18 number, which console logs the result.\n    function bound(UD21x18 x, uint128 min, uint128 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(bound(uint256(x.unwrap()), uint256(min), uint256(max))));\n    }\n\n    /// @dev Helper function to bound a UD21x18 number, which does NOT console log the result.\n    function _bound(UD21x18 x, uint128 min, uint128 max) internal pure returns (UD21x18) {\n        return UD21x18.wrap(uint128(_bound(uint256(x.unwrap()), uint256(min), uint256(max))));\n    }\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                      UD60X18\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @dev Helper function to bound a UD60x18 number, which console logs the result.\n    function bound(UD60x18 x, UD60x18 min, UD60x18 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(bound(x.unwrap(), min.unwrap(), max.unwrap()));\n    }\n\n    /// @dev Helper function to bound a UD60x18 number, which does NOT console log the result.\n    function _bound(UD60x18 x, UD60x18 min, UD60x18 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(_bound(x.unwrap(), min.unwrap(), max.unwrap()));\n    }\n\n    /// @dev Helper function to bound a UD60x18 number, which console logs the result.\n    function bound(UD60x18 x, uint256 min, UD60x18 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(bound(x.unwrap(), min, max.unwrap()));\n    }\n\n    /// @dev Helper function to bound a UD60x18 number, which does NOT console log the result.\n    function _bound(UD60x18 x, uint256 min, UD60x18 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(_bound(x.unwrap(), min, max.unwrap()));\n    }\n\n    /// @dev Helper function to bound a UD60x18 number, which console logs the result.\n    function bound(UD60x18 x, UD60x18 min, uint256 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(bound(x.unwrap(), min.unwrap(), max));\n    }\n\n    /// @dev Helper function to bound a UD60x18 number, which does NOT console log the result.\n    function _bound(UD60x18 x, UD60x18 min, uint256 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(_bound(x.unwrap(), min.unwrap(), max));\n    }\n\n    /// @dev Helper function to bound a UD60x18 number, which console logs the result.\n    function bound(UD60x18 x, uint256 min, uint256 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(bound(x.unwrap(), min, max));\n    }\n\n    /// @dev Helper function to bound a UD60x18 number, which does NOT console log the result.\n    function _bound(UD60x18 x, uint256 min, uint256 max) internal pure returns (UD60x18) {\n        return UD60x18.wrap(_bound(x.unwrap(), min, max));\n    }\n}\n"
  }
]