[
  {
    "path": ".github/dependabot.yml",
    "content": "# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\nversion: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/CompatHelper.yml",
    "content": "name: CompatHelper\non:\n  schedule:\n    - cron: 8 14 * * *\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Pkg.add(\"CompatHelper\")\n        run: julia -e 'using Pkg; Pkg.add(\"CompatHelper\")'\n      - name: CompatHelper.main()\n        run: julia -e 'using CompatHelper; CompatHelper.main()'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }}\n"
  },
  {
    "path": ".github/workflows/TagBot.yml",
    "content": "name: TagBot\non:\n  issue_comment:\n    types:\n      - created\n  workflow_dispatch:\njobs:\n  TagBot:\n    if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: JuliaRegistries/TagBot@v1\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          ssh: ${{ secrets.DOCUMENTER_KEY }}\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: \"master\"\n    tags: [\"*\"]\n    paths:\n      - '.github/workflows/ci.yml'\n      - 'src/**'\n      - 'test/**'\n      - 'Project.toml'\n  pull_request:\n    paths:\n      - '.github/workflows/ci.yml'\n      - 'src/**'\n      - 'test/**'\n      - 'Project.toml'\n  release:\n\nconcurrency:\n  # Skip intermediate builds: always.\n  # Cancel intermediate builds: only if it is a pull request build.\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}\n\njobs:\n  test:\n    name: Julia ${{ matrix.julia-version }} - ${{ matrix.os }} - ${{ matrix.julia-arch }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        julia-version:\n          - \"min\"\n          - \"lts\"\n          - \"1\"\n          - \"pre\"\n        os:\n          - ubuntu-latest\n          - macos-latest\n          - windows-latest\n        julia-arch:\n          - \"default\"\n        # Until minimum supported version is v1.6, we can't test on Apple\n        # Silicon macOS for that version and we need to use Julia v1.8 instead\n        exclude:\n          - julia-version: \"min\"\n            os: macos-latest\n        include:\n          - julia-version: \"1.8\"\n            os: macos-latest\n            julia-arch: \"default\"\n    steps:\n      - uses: actions/checkout@v6\n      - uses: julia-actions/setup-julia@v3\n        with:\n          version: ${{ matrix.julia-version }}\n          arch: ${{ matrix.julia-arch }}\n      - uses: julia-actions/cache@v3\n      - uses: julia-actions/julia-buildpkg@v1\n      - uses: julia-actions/julia-runtest@v1\n      - uses: julia-actions/julia-processcoverage@v1\n      - uses: codecov/codecov-action@v6\n        with:\n          files: lcov.info\n          fail_ci_if_error: false\n      - uses: coverallsapp/github-action@v2\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path-to-lcov: lcov.info\n          flag-name: run-${{ join(matrix.*, '-') }}\n          parallel: true\n"
  },
  {
    "path": ".github/workflows/documentation.yaml",
    "content": "name: Documentation\n\non:\n  push:\n    branches: \"master\"\n    tags: [\"*\"]\n    paths:\n      - '.github/workflows/documentation.yaml'\n      - 'src/**'\n      - 'docs/**'\n      - 'Project.toml'\n  pull_request:\n    paths:\n      - '.github/workflows/documentation.yaml'\n      - 'src/**'\n      - 'docs/**'\n      - 'Project.toml'\n  release:\n\nconcurrency:\n  # Skip intermediate builds: always.\n  # Cancel intermediate builds: only if it is a pull request build.\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}\n\njobs:\n  Documentation:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: julia-actions/setup-julia@v3\n        with:\n          version: 1\n      - uses: julia-actions/cache@v3\n      - uses: julia-actions/julia-docdeploy@v1\n        env:\n          DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}\n      - uses: actions/upload-artifact@v7\n        with:\n          name: documentation-build\n          path: docs/build\n          retention-days: 90\n"
  },
  {
    "path": ".gitignore",
    "content": "# Files generated by invoking Julia with --code-coverage\n*.jl.cov\n*.jl.*.cov\n\n# Files generated by invoking Julia with --track-allocation\n*.jl.mem\n\n# Build artifacts for creating documentation generated by the Documenter package\ndocs/build/\ndocs/site/\n\n# File generated by Pkg, the package manager, based on a corresponding Project.toml\n# It records a fixed state of all packages used by the project. As such, it should not be\n# committed for packages, but should be committed for applications that require a static\n# environment.\nManifest.toml\n\n*~\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The Unitful.jl package is licensed under the MIT \"Expat\" License:\n\n> Copyright (c) 2016: California Institute of Technology and\n> [other contributors](https://github.com/JuliaPhysics/Unitful.jl/graphs/contributors).\n>\n> Permission is hereby granted, free of charge, to any person obtaining\n> a copy of this software and associated documentation files (the\n> \"Software\"), to deal in the Software without restriction, including\n> without limitation the rights to use, copy, modify, merge, publish,\n> distribute, sublicense, and/or sell copies of the Software, and to\n> permit persons to whom the Software is furnished to do so, subject to\n> the following conditions:\n>\n> The above copyright notice and this permission notice shall be\n> included in all copies or substantial portions of the Software.\n>\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nPortions borrow from [EngUnits.jl](https://github.com/dhoegh/EngUnits.jl/blob/master/LICENSE.md),\nwhich is (c) 2016: Daniel Høegh. Unitful.jl's fastmath implementation and tests\ndraw heavily on those found in [Julia](https://github.com/JuliaLang/julia/blob/master/LICENSE.md).\n\nNeither the name of the California Institute of Technology (“Caltech”) nor the names of its contributors (and/or sponsors) may be used to endorse or promote products derived from this software without specific prior written permission.\n\nAndrew Keller (original package author, assigning his copyright to California Institute of Technology) acknowledges the support of an IQIM Postdoctoral Scholarship (Institute for Quantum Information and Matter, an NSF Physics Frontiers Center, NSF Grant PHY-1125565).\n"
  },
  {
    "path": "NEWS.md",
    "content": "# Unitful.jl changelog\n\n## v1.28.0 (2026-01-29)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Dimensionless quantities now support `iseven` and `isodd` ([#829](https://github.com/JuliaPhysics/Unitful.jl/pull/829)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Quantities that have equal values and equal units now have the same hash ([#833](https://github.com/JuliaPhysics/Unitful.jl/pull/833)). For now, quantities that are equal (`isequal`) but have different units still have different hashes, see [#379](https://github.com/JuliaPhysics/Unitful.jl/issues/379).\n\n## v1.27.0 (2025-12-08)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `NaNMath.pow` and `NaNMath.sqrt` from [NaNMath.jl](https://github.com/JuliaMath/NaNMath.jl) are supported via a package extension ([#824](https://github.com/JuliaPhysics/Unitful.jl/pull/824)).\n\n## v1.26.0 (2025-12-05)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The aliases `degC` and `degF` for `°C` and `°F` are added ([#826](https://github.com/JuliaPhysics/Unitful.jl/pull/826)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Correct LaTeX printing of affine units ([#825](https://github.com/JuliaPhysics/Unitful.jl/pull/825)).\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Fix a world-age warning on Julia 1.12 ([#819](https://github.com/JuliaPhysics/Unitful.jl/issues/819)).\n\n## v1.25.1 (2025-10-18)\n\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Fix a parsing error on Julia 1.13 ([#817](https://github.com/JuliaPhysics/Unitful.jl/issues/817)).\n\n## v1.25.0 (2025-09-16)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Quantities and units can now be converted to a LaTeX representation using [`Latexify.jl`](https://github.com/korsbo/Latexify.jl). This is provided via a package extension and replaces the [UnitfulLatexify.jl](https://github.com/gustaphe/UnitfulLatexify.jl) package ([#795](https://github.com/JuliaPhysics/Unitful.jl/pull/795)).\n* This package now requires Julia ≥ 1.6.\n\n## v1.24.0 (2025-07-31)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The alias `deg` for `°` is added ([#764](https://github.com/JuliaPhysics/Unitful.jl/pull/764)).\n\n## v1.23.1 (2025-06-10)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Fix a world-age issue with the new mechanism to preserve the floating-point precision on unit conversion ([#790](https://github.com/JuliaPhysics/Unitful.jl/issues/790)).\n\n## v1.23.0 (2025-06-08)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) On Julia ≥ 1.9, dimensionless quantities can now be converted to `ForwardDiff.Dual`. This is important for compatibility with the SciML ecosystem and is provided via a package extension ([#765](https://github.com/JuliaPhysics/Unitful.jl/pull/765)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) On Julia ≥ 1.9, `@printf` and `@sprintf` can now be used with Unitful quantities. The specified format is applied to the numeric part of the quantity and the unit is appended to that. This is provided via a package extension ([#772](https://github.com/JuliaPhysics/Unitful.jl/pull/772)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Certain unit conversions involving units that are defined using non-integer exponents no longer error ([#783](https://github.com/JuliaPhysics/Unitful.jl/pull/783)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) `uconvert` now preserves the floating-point precision of quantities in a non-breaking way ([#782](https://github.com/JuliaPhysics/Unitful.jl/pull/782)).\n\n## v1.22.1 (2025-05-13)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) The behaviour to preserve the floating-point precision of quantities ([#754](https://github.com/JuliaPhysics/Unitful.jl/pull/754), added in v1.22.0) is reverted because it is not compatible with [IntervalArithmetic.jl](https://github.com/JuliaIntervals/IntervalArithmetic.jl) (see [#758](https://github.com/JuliaPhysics/Unitful.jl/issues/758)). The feature will be added in a non-breaking way in a future release.\n\n## v1.22.0 (2025-01-02)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `Base.big` can now be used with quantities ([#755](https://github.com/JuliaPhysics/Unitful.jl/pull/755)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Using `Base.convert` to convert to a unitless quantity no longer errors ([#724](https://github.com/JuliaPhysics/Unitful.jl/pull/724)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Using `Base.convert` to convert to a mixed logarithmic quantity no longer returns wrong results. In cases that returned a result even though it was unknown whether the quantity was a power or root-power quantity, an error is thrown instead ([#724](https://github.com/JuliaPhysics/Unitful.jl/pull/724)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) `uconvert` now preserves the floating-point precision of quantities ([#754](https://github.com/JuliaPhysics/Unitful.jl/pull/754)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) When printing arrays, quantities are now aligned at the decimal point just like unitless numbers ([#752](https://github.com/JuliaPhysics/Unitful.jl/pull/752)).\n\n## v1.21.1 (2024-11-29)\n\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) `Base.cis` now returns more accurate results for arguments in degrees. This unfortunately is slower. If you prioritize speed over precision you can convert to `NoUnits` before calling `cis` or use `@fastmath` ([#745](https://github.com/JuliaPhysics/Unitful.jl/pull/745)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Trigonometric functions now return more accurate results for arguments in degrees when using `BigFloat` precision and `@fastmath` ([#750](https://github.com/JuliaPhysics/Unitful.jl/pull/750)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Performance of trigonometric functions with `@fastmath` is improved for some argument types ([#750](https://github.com/JuliaPhysics/Unitful.jl/pull/750)).\n* The documentation now contains a list of all units and constants defined in this package ([#729](https://github.com/JuliaPhysics/Unitful.jl/pull/729)).\n\n## v1.21.0 (2024-07-19)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Arithmetic between `Dates.TimeType` and `Unitful.Time` is added, e.g., `Dates.now() + 1u\"hr\"` now works ([#731](https://github.com/JuliaPhysics/Unitful.jl/pull/731)).\n\n## v1.20.0 (2024-05-17)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `isapprox` with arrays of quantities now supports the `nans` keyword argument ([#719](https://github.com/JuliaPhysics/Unitful.jl/pull/719)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `isapprox` with arrays of quantities now calculates the default `rtol` correctly, i.e., `rtol` defaults to zero if a positive `atol` is specified, like in the scalar or unitless case ([#719](https://github.com/JuliaPhysics/Unitful.jl/pull/719)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `isapprox` with arrays of quantities now checks whether `norm(x-y) ≤ max(atol, rtol*max(norm(x), norm(y)))`, like in the scalar or unitless case, instead of `norm(x-y) ≤ atol + rtol*max(norm(x),\n  norm(y))` ([#719](https://github.com/JuliaPhysics/Unitful.jl/pull/719)).\n\n## v1.19.1 (2024-05-13)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Broadcasting `upreferred`, `ustrip`, or a unit (when used as a conversion function) over ranges now works correctly again ([#711](https://github.com/JuliaPhysics/Unitful.jl/pull/711), [#715](https://github.com/JuliaPhysics/Unitful.jl/pull/715)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Broadcasting `upreferred`, `ustrip`, or a unit (when used as a conversion function) over a `StepRange` now returns a `StepRangeLen` when the conversion results in floating-point numbers ([#715](https://github.com/JuliaPhysics/Unitful.jl/pull/715)).\n\n## v1.19.0 (2023-11-29)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The dimensionless units parts per cent mille (`pcm`, 10^-5), parts per million (`ppm`, 10^-6), parts per billion (`ppb`, 10^-9), parts per trillion (`ppt`, 10^-12), and parts per quadrillion (`ppq`, 10^-15) are added ([#699](https://github.com/JuliaPhysics/Unitful.jl/pull/699)).\n\n## v1.18.0 (2023-11-13)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The two-argument versions of `nextfloat` and `prefloat` now allow quantities as their first argument ([#692](https://github.com/JuliaPhysics/Unitful.jl/pull/692)).\n\n## v1.17.0 (2023-08-24)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The standard atmosphere (`atm`) now accepts SI prefixes, e.g., `μatm` is defined ([#664](https://github.com/JuliaPhysics/Unitful.jl/pull/664)).\n\n## v1.16.3 (2023-08-14)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Calling `min` and `max` with quantities of different units can no longer return wrong results due to floating-point overflow in the unit conversion ([#675](https://github.com/JuliaPhysics/Unitful.jl/pull/675)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `min` and `max` now handle quantities with `NaN` values correctly ([#675](https://github.com/JuliaPhysics/Unitful.jl/pull/675)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `Base.hastypemax` is now correctly implemented for quantity types ([#674](https://github.com/JuliaPhysics/Unitful.jl/pull/674)).\n\n## v1.16.2 (2023-08-05)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) The conversion factors between units can no longer be wrongly calculated as `NaN`, `Inf`, or `0` (which could happen, e.g., in the case of large exponents). The conversion factor is now calculated correctly in more cases, and an error is thrown if it cannot be calculated due to floating-point over- or underflow ([#648](https://github.com/JuliaPhysics/Unitful.jl/pull/648)).\n\n## v1.16.1 (2023-08-02)\n\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Replaced occurrences of single-argument `@doc` for duplicating docstrings, which could lead to errors when creating a Docker image with Julia 1.9 and Unitful ([#671](https://github.com/JuliaPhysics/Unitful.jl/pull/671)).\n\n## v1.16.0 (2023-08-01)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The derived dimension `MolarMass` (`𝐌/𝐍`) is added ([#663](https://github.com/JuliaPhysics/Unitful.jl/pull/663)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) Dimensionless quantities now support the `tanpi` function added in Julia 1.10 ([#620](https://github.com/JuliaPhysics/Unitful.jl/pull/620)).\n\n## v1.15.0 (2023-07-05)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Support for [InverseFunctions.jl](https://github.com/JuliaMath/InverseFunctions.jl) is extended to all supported Julia versions. On Julia < 1.9, InverseFunctions.jl is added as a regular dependency ([#652](https://github.com/JuliaPhysics/Unitful.jl/pull/652)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) On Julia ≥ 1.9, [ConstructionBase.jl](https://github.com/JuliaObjects/ConstructionBase.jl) is now a weak dependency. On older versions, it is still a regular dependency. ([#658](https://github.com/JuliaPhysics/Unitful.jl/pull/658)).\n\n## v1.14.0 (2023-05-11)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) On Julia ≥ 1.9, [InverseFunctions.jl](https://github.com/JuliaMath/InverseFunctions.jl) can be used to get the inverse function of `Base.Fix1(ustrip, u::Units)` ([#622](https://github.com/JuliaPhysics/Unitful.jl/pull/622)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `<=` now works correctly for `AbstractQuantity{T}` when `T` is a type for which `<=(x::T,y::T)` is different than `x < y || x == y` ([#646](https://github.com/JuliaPhysics/Unitful.jl/pull/646)).\n\n## v1.13.1 (2023-04-15)\n\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Adapt test suite for Julia 1.9 ([#643](https://github.com/JuliaPhysics/Unitful.jl/pull/643)).\n\n## v1.13.0 (2023-04-11)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `Base.sleep` now accepts quantities of time as argument ([#628](https://github.com/JuliaPhysics/Unitful.jl/pull/628)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) `Base.copysign` and `Base.flipsign` can now be called with a plain number as first argument and a quantity as second argument ([#612](https://github.com/JuliaPhysics/Unitful.jl/pull/612)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) All known method ambiguities of the package are resolved ([#606](https://github.com/JuliaPhysics/Unitful.jl/pull/606), [#626](https://github.com/JuliaPhysics/Unitful.jl/pull/626)).\n* The package now has a logo. It was created by Leandro Martínez and shows the International Prototype of the Kilogram ([#567](https://github.com/JuliaPhysics/Unitful.jl/pull/567), [#634](https://github.com/JuliaPhysics/Unitful.jl/pull/634)).\n\n## v1.12.4 (2023-02-27)\n\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) `@fastmath` with quantities now uses functions from `Base.FastMath` instead of intrinsic functions, because the latter may be removed at any time ([#617](https://github.com/JuliaPhysics/Unitful.jl/pull/617)).\n\n## v1.12.3 (2023-02-10)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Multiplication is no longer assumed to be commutative, which is wrong for, e.g., quaternions ([#608](https://github.com/JuliaPhysics/Unitful.jl/pull/608)).\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Adapt the documentation on extending Unitful for Julia ≥ 1.9 ([#600](https://github.com/JuliaPhysics/Unitful.jl/pull/600)).\n\n## v1.12.2 (2022-11-30)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Broadcasting `upreferred` over floating-point ranges now works again ([#577](https://github.com/JuliaPhysics/Unitful.jl/pull/577)).\n\n## v1.12.1 (2022-11-18)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Fixed `istriu`/`istril` for affine quantities ([#572](https://github.com/JuliaPhysics/Unitful.jl/pull/572)).\n\n## v1.12.0 (2022-09-17)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Dimensionless quantities now support `cispi`, `sincospi`, and `modf` ([#533](https://github.com/JuliaPhysics/Unitful.jl/pull/533), [#539](https://github.com/JuliaPhysics/Unitful.jl/pull/539)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Ranges of affine quantities are now printed correctly ([#551](https://github.com/JuliaPhysics/Unitful.jl/pull/551)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) The non-existent functions `convertr` and `convertrp` are no longer exported ([#530](https://github.com/JuliaPhysics/Unitful.jl/pull/530)).\n\n## v1.11.0 (2022-02-10)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `Base.zero` now works on heterogeneous arrays of quantities, e.g., `zero([1m, 1s]) == [0m, 0s]` ([#533](https://github.com/JuliaPhysics/Unitful.jl/pull/533), [#516](https://github.com/JuliaPhysics/Unitful.jl/pull/516)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `StepRangeLen`s of complex-valued quantities are now printed correctly ([#513](https://github.com/JuliaPhysics/Unitful.jl/pull/513)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Method ambiguities of `Base._range` are resolved ([#514](https://github.com/JuliaPhysics/Unitful.jl/pull/514)).\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Updated `range` implementation for Julia ≥ 1.8 ([#514](https://github.com/JuliaPhysics/Unitful.jl/pull/514)).\n\n## v1.10.1 (2022-01-03)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Fixed `isapprox` for arrays of complex-valued quantities ([#468](https://github.com/JuliaPhysics/Unitful.jl/pull/468)).\n\n## v1.10.0 (2021-12-27)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Dimensions and units can now be documented by adding a docstring before the `@dimension`, `@refunit`, `@unit`, and `@affineunit` macro calls. The `@dimension`, `@derived_dimension`, `@refunit`, and `@unit` macros have an optional boolean argument `autodocs` to add autogenerated docstrings to some objects generated by these macros. All dimensions, units and constants defined in this package now have docstrings ([#476](https://github.com/JuliaPhysics/Unitful.jl/pull/476)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Calling `preferunits` with non-pure units (e.g., `preferunits(C/ms)`) no longer results in wrong behavior ([#478](https://github.com/JuliaPhysics/Unitful.jl/pull/478)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Fixed some invalidations to improve compile times ([#509](https://github.com/JuliaPhysics/Unitful.jl/pull/509)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Broadcasting `ustrip`, `upreferred`, and `*` over a range now returns another range instead of a `Vector` ([#501](https://github.com/JuliaPhysics/Unitful.jl/pull/501), [#503](https://github.com/JuliaPhysics/Unitful.jl/pull/503)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) `LinearAlgebra.norm` now returns a floating-point quantity, which matches the behavior for `Base` numbers ([#500](https://github.com/JuliaPhysics/Unitful.jl/pull/500)).\n\n## v1.9.2 (2021-11-12)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) The functions `Unitful.cos_fast`, `Unitful.sin_fast`, and `Unitful.tan_fast` are removed. Due to an implementation error, they always threw a `MethodError`, so removing them is not breaking. This fixes a warning during precompilation ([#497](https://github.com/JuliaPhysics/Unitful.jl/pull/497)).\n\n## v1.9.1 (2021-10-27)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Multiplying a `StepRangeLen` by `Units` now preserves the floating-point precision ([#485](https://github.com/JuliaPhysics/Unitful.jl/pull/485)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Make `^(::AbstractQuantity, ::Rational)` inferrable on Julia ≥ 1.8 ([#487](https://github.com/JuliaPhysics/Unitful.jl/pull/487)).\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Updated multiplication of range and quantity for Julia ≥ 1.8 compatibility ([#489](https://github.com/JuliaPhysics/Unitful.jl/pull/489), [#495](https://github.com/JuliaPhysics/Unitful.jl/pull/495)).\n\n## v1.9.0 (2021-07-16)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `deg2rad` and `rad2deg` can now be used to convert between `°` and `rad` ([#459](https://github.com/JuliaPhysics/Unitful.jl/pull/459)).\n\n## v1.8.0 (2021-05-31)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The `IOContext` property `:fancy_exponent` can be used to control the printing of exponents in units (i.e., `m²` or `m^2`). Previously, this could only be done by setting the environment variable `UNITFUL_FANCY_EXPONENTS`. The `:fancy_exponent` property overrides the environment variable ([#446](https://github.com/JuliaPhysics/Unitful.jl/pull/446)).\n\n## v1.7.0 (2021-04-02)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The functions `dimension`, `unit`, `absoluteunit`, `upreferred`, and `numtype` now support `AbstractQuantity` (instead of just `Quantity`) arguments ([#431](https://github.com/JuliaPhysics/Unitful.jl/pull/431)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) Support for conversion between `Unitful.Time` and `Dates.FixedPeriod` types is added ([#331](https://github.com/JuliaPhysics/Unitful.jl/pull/331)).\n\n## v1.6.0 (2021-02-14)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Support for the `Base.unordered` function is added ([#406](https://github.com/JuliaPhysics/Unitful.jl/pull/406)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The CGS units Gauss (`Gauss`), Oersted (`Oe`), and Maxwell (`Mx`) are added ([#397](https://github.com/JuliaPhysics/Unitful.jl/pull/397)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Removed a wrong use of `@eval` that broke precompilation ([#417](https://github.com/JuliaPhysics/Unitful.jl/pull/417)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) The traits `Base.ArithmeticStyle` and `Base.OrderStyle` are now implemented correctly to support number types that are not defined in `Base` ([#407](https://github.com/JuliaPhysics/Unitful.jl/pull/407)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `==` and `isequal` now work correctly for `Gain`s and `Level`s with bignums ([#404](https://github.com/JuliaPhysics/Unitful.jl/pull/404)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) `range(start; step, length)` now always creates a functioning range when `start` and `step` have different units ([#411](https://github.com/JuliaPhysics/Unitful.jl/pull/411)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) It is no longer possible to create a `Level` with non-real value or reference quantity ([#400](https://github.com/JuliaPhysics/Unitful.jl/pull/400), [#421](https://github.com/JuliaPhysics/Unitful.jl/pull/421)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Macro hygiene is improved ([#390](https://github.com/JuliaPhysics/Unitful.jl/pull/390)).\n\n## v1.5.0 (2020-10-21)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Dimensionless quantities now support inverse and hyperbolic trig functions ([#387](https://github.com/JuliaPhysics/Unitful.jl/pull/387)).\n\n## v1.4.1 (2020-09-17)\n\n* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Adapt test suite to Julia ≥ 1.6 type parameter printing ([#380](https://github.com/JuliaPhysics/Unitful.jl/pull/380)).\n\n## v1.4.0 (2020-08-11)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) It is now possible to divide an array by units ([#369](https://github.com/JuliaPhysics/Unitful.jl/pull/369)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Complex and mixed quantities are now printed with brackets ([#366](https://github.com/JuliaPhysics/Unitful.jl/pull/366)).\n\n## v1.3.0 (2020-06-26)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `isless` is now defined for logarithmic quantities ([#315](https://github.com/JuliaPhysics/Unitful.jl/pull/315)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Calling `div`, `rem`, etc. with affine quantities now errors ([#354](https://github.com/JuliaPhysics/Unitful.jl/pull/354)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Custom printing of types was removed ([#322](https://github.com/JuliaPhysics/Unitful.jl/pull/322)).\n\n## v1.2.1 (2020-05-26)\n\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Fix an error when converting units with fractional power ([#335](https://github.com/JuliaPhysics/Unitful.jl/pull/335)).\n\n## v1.2.0 (2020-05-10)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Year` now allows SI prefixes ([#320](https://github.com/JuliaPhysics/Unitful.jl/pull/320)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Unit conversions can now return integer-valued quantities if the conversion factor is whole ([#323](https://github.com/JuliaPhysics/Unitful.jl/pull/323)).\n\n## v1.1.0 (2020-04-09)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `div`, `fld`, `cld` now allow arguments of different dimensions as long as one of them is a plain number (i.e., not an `AbstractQuantity`), e.g., `div(10m, 3) == 3m` and `cld(10, 3m) == 4/m` ([#317](https://github.com/JuliaPhysics/Unitful.jl/pull/317)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) Unicode superscript can now be used to to display powers in units and dimensions (e.g., `m²` instead of `m^2`). The `UNITFUL_FANCY_EXPONENTS` environment variable can be used to control whether unicode powers are used or not ([#297](https://github.com/JuliaPhysics/Unitful.jl/pull/297)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Year` (`yr`) is defined, equal to 365.25 days ([#288](https://github.com/JuliaPhysics/Unitful.jl/pull/288)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `round` with the `digits`/`sigdigits` keyword now works correctly for quantities that are not based on floating-point numbers. It returns a float-based quantity in those cases ([#308](https://github.com/JuliaPhysics/Unitful.jl/pull/308)).\n\n## v1.0.0 (2020-01-27)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The `uparse` function can be used to parse units and quantities from a string ([#298](https://github.com/JuliaPhysics/Unitful.jl/pull/298)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The constructors `Float16`, `Float32`, `Float64`, and `BigFloat` can be used to convert a quantity to one based on the specified floating-point type, e.g., `Float64(1m) === 1.0m`. The `float` function can be used to convert a quantity to an appropriate floating-point type ([#296](https://github.com/JuliaPhysics/Unitful.jl/pull/296)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Pertenthousand` (`‱`) is added ([#294](https://github.com/JuliaPhysics/Unitful.jl/pull/294)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Calling the two-argument `atan` with quantities that have the same numeric type and dimension but different units no longer errors ([#293](https://github.com/JuliaPhysics/Unitful.jl/pull/293)).\n\n## v0.18.0 (2019-11-27)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) `Quantity` types now support the `constructorof` function from the [ConstructionBase.jl](https://github.com/JuliaObjects/ConstructionBase.jl) package ([#280](https://github.com/JuliaPhysics/Unitful.jl/pull/280)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) Using units as conversion functions now supports `missing` ([#278](https://github.com/JuliaPhysics/Unitful.jl/pull/278)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Angstrom` (`Å` or `angstrom`) is added ([#271](https://github.com/JuliaPhysics/Unitful.jl/pull/271)).\n\n## v0.17.0 (2019-09-08)\n\n* ![BREAKING:](https://img.shields.io/badge/-BREAKING-red) The unit `rps` (revolutions per second) is now equal to `2π*rad/s` instead of `1/s` and the unit `rpm` (revolutions per minute) is now equal to `2π*rad/minute` instead of `1/minute` ([#268](https://github.com/JuliaPhysics/Unitful.jl/pull/268)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The derived dimensions `MassFlow` (`𝐌/𝐓`), `MolarFlow` (`𝐍/𝐓`), and `VolumeFlow` (`𝐋^3/𝐓`) are added ([#269](https://github.com/JuliaPhysics/Unitful.jl/pull/269)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The dimensions power density (`𝐌 𝐋^-1 𝐓^-3`) and work (`𝐋^2 𝐌 𝐓^-2`) are marked as power-like for use with logarithmic quantities ([#267](https://github.com/JuliaPhysics/Unitful.jl/pull/267)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) `zero(::Type{<:AbstractQuantity{T,D}}) where {T,D}` can be used to get an additive identity with numeric type `T` and dimension `D` ([#266](https://github.com/JuliaPhysics/Unitful.jl/pull/266)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Molar` (`M`) is added ([#258](https://github.com/JuliaPhysics/Unitful.jl/pull/258)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) `Unitful.register` now extends `Unitful.basefactors`, so packages that define units don’t have to do it themselves ([#251](https://github.com/JuliaPhysics/Unitful.jl/pull/251)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Ranges of quantities are now printed in a more concise way ([#256](https://github.com/JuliaPhysics/Unitful.jl/pull/256)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Angular degrees are now printed without a space between the number and unit, in compliance with the SI standard ([#255](https://github.com/JuliaPhysics/Unitful.jl/pull/255)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `zero` now errors if the dimension of its argument is unspecified ([#266](https://github.com/JuliaPhysics/Unitful.jl/pull/266)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `Unitful.promote_to_derived` works again ([#252](https://github.com/JuliaPhysics/Unitful.jl/pull/252)).\n\n## v0.16.0 (2019-07-01)\n\n* ![BREAKING:](https://img.shields.io/badge/-BREAKING-red) The physical constants are updated to the CODATA 2018 recommended values ([#235](https://github.com/JuliaPhysics/Unitful.jl/pull/235)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) On Julia v1, the rounding functions `round`, `ceil`, `floor`, and `trunc` now accept all keyword arguments that are supported for plain numbers. In addition, the first argument to these functions can be a unit instead of a type ([#246](https://github.com/JuliaPhysics/Unitful.jl/pull/246), [#249](https://github.com/JuliaPhysics/Unitful.jl/pull/249), [#250](https://github.com/JuliaPhysics/Unitful.jl/pull/250)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The functions `Base.complex`, `Base.reim`, and `Base.widen` can now be called with unitful quantities ([#227](https://github.com/JuliaPhysics/Unitful.jl/pull/227)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The function `upreferred` now supports `missing` ([#224](https://github.com/JuliaPhysics/Unitful.jl/pull/224)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) Two-argument and three-argument `ustrip` now support dimensionless quantities and `missing` ([#212](https://github.com/JuliaPhysics/Unitful.jl/pull/212)).\n* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Better support for number types that customize their `MIME\"text/plain\"` printing ([#213](https://github.com/JuliaPhysics/Unitful.jl/pull/213)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Ranges which use `Base.TwicePrecision` internally now work correctly ([#245](https://github.com/JuliaPhysics/Unitful.jl/pull/245)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Fixed some issues around use of `@generated` functions that could lead to world-age errors or wrong behavior ([#233](https://github.com/JuliaPhysics/Unitful.jl/pull/233), [#243](https://github.com/JuliaPhysics/Unitful.jl/pull/243)).\n\n## v0.15.0 (2019-03-05)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) The functions `uconvert`, `ustrip`, `unit`, and `dimension` as well as arithmetic with units now support `missing` ([#208](https://github.com/JuliaPhysics/Unitful.jl/pull/208)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) Two-argument `ustrip(unit, x)` and three-argument `ustrip(T, unit, x)` methods are added ([#205](https://github.com/JuliaPhysics/Unitful.jl/pull/205)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The `AbstractQuantity{T,D,U}` type is defined to support defining quantity types other than `Quantity{T,D,U}` ([#204](https://github.com/JuliaPhysics/Unitful.jl/pull/204)).\n* ![Feature:](https://img.shields.io/badge/-feature-green) The derived dimensions `Molarity` (`𝐍/𝐋^3`) and `Molality` (`𝐍/𝐌`) are added ([#198](https://github.com/JuliaPhysics/Unitful.jl/pull/198)).\n* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Multiplying a range by units now works correctly ([#206](https://github.com/JuliaPhysics/Unitful.jl/pull/206)).\n\n## Older changes\n\n- v0.14.0\n  - Support for `digits` kwarg (#196).\n  - Try to support precompilation with `u_str` macro (#201).\n- v0.13.0\n  - Implement affine quantities for better temperature handling (#177, #182).\n  - Rename `°Ra` to `Ra` to emphasize that it is an absolute scale.\n  - Fix some precompilation issues (#161).\n  - Add `Velocity`, `Acceleration`, `Density` derived dimensions (#187).\n  - Days display as `d` now (#184).\n  - Type signature of `Quantity`s has been simplified. Helps with reading error messages (#183).\n  - Support `isequal` with `NaN` quantities (#172).\n- v0.12.0\n  - Bug fixes.\n  - Support carrier-to-noise-density ratio (C/N0) in dB-Hz.\n  - Added dimensions: `DField`, `EField`, `ElectricDipoleMoment`, `ElectricQuadrupoleMoment`, `MagneticDipoleMoment`.\n  - Added unit: `barn`.\n  - Some documentation improvements.\n- v0.11.0--v0.9.0\n  - Fixes for Julia 0.7 update, primarily.\n  - Some new TwicePrecision functionality for quantities.\n- v0.8.0\n  - Add Rydberg constant, unified atomic mass unit, mils, rpm, rps, percent, permille.\n  - Introduce/rename derived dimensions: ElectricalConductivity, ElectricalResistivity,\n    ElectricalConductance, ElectricalResistance.\n  - Fix some Julia 0.7 deprecations.\n  - This will probably be the last release that supports Julia 0.6.\n- v0.7.1\n  - Bug fixes, mainly.\n- v0.7.0\n  - Implement `mod2pi` for degrees, cleanup display of degree units.\n  - Tweak implementation of `Gain` types for usability.\n  - Implement `zero` and `one` for `Level` and `Gain`.\n  - Add a few more cgs units.\n  - Tests pass on 32-bit systems, for the first time in a long time (ever?).\n- v0.6.1\n  - Permit symbols that are bound to `Number`s to be used in `u_str` macro, such that\n    π and other non-literal numbers can be used.\n  - Add some cgs units and a few dimensions [#115](https://github.com/JuliaPhysics/Unitful.jl/pull/115).\n  - Fix a comparison / promotion bug introduced in v0.6.0.\n- v0.6.0\n  - Restore compatibility with 0.7.0-DEV.\n- v0.5.1\n  - Dimensionless quantities no longer lose their units when dividing by a real number.\n  - Ranges constructed via `range` or `colon` should work more reliably (e.g., 0:10°:350° works now).\n- v0.5.0\n  - Add `dBΩ` and `dBS` to permit working with impedances and admittances in dB. These are\n    used in the Touchstone format and in microwave measurements.\n  - Implement `angle` for `Quantity{<:Complex}`.\n  - Implement `float` for `Gain`, `Level`.\n  - Replace `fieldratio` and `rootpowerratio` with `uconvertrp`.\n    - Permits unit conversion between `NoUnits` and `dB`, etc. by presuming unitless ratios\n      are of root-power quantities (hence the `rp` after `uconvert`).\n    - `uconvertrp` has generic fallbacks and can be used as a drop-in replacement for\n      `uconvert` otherwise.\n  - Likewise, replace `powerratio` with `uconvertp` for ratios of power quantities.\n  - Introduce `convertrp` and `convertp`. These are like `convert` but they make\n    similar assumptions about unitless ratios being of power or root-power quantities,\n    respectively.\n  - Implement more division operations for `Gain`s (accidental omissions)\n- v0.4.0\n  - Introduce logarithmic quantities (experimental!)\n  - Update syntax for Julia 0.6 and reorganize code for clarity.\n  - Redefine `ustrip(x::Quantity) = ustrip(x.val)`. In most cases, this is unlikely to\n    affect user code. The generic fallback `ustrip(x::Number)` remains unchanged.\n  - `isapprox(1.0u\"m\",5)` returns `false` instead of throwing a `DimensionError`,\n    in keeping with the behavior of an equality check (`==`).\n  - Display of some units has changed to match their symbols [#104](https://github.com/JuliaPhysics/Unitful.jl/issues/104).\n  - Don't export `cd` from Unitful.DefaultSymbols in order to avoid conflicts [#102](https://github.com/JuliaPhysics/Unitful.jl/issues/102).\n  - Deprecated `dimension(x::AbstractArray{T}) where T<:Number`, use broadcasting instead.\n  - Deprecated `dimension(x::AbstractArray{T}) where T<:Units`, use broadcasting instead.\n  - Deprecated `ustrip(A::AbstractArray{T}) where T<:Number`, use broadcasting instead.\n  - Deprecated `ustrip(A::AbstractArray{T}) where T<:Quantity`, use broadcasting instead.\n- v0.3.0\n  - Require Julia 0.6\n  - Adds overloads for `rand` and `ones` [#96](https://github.com/JuliaPhysics/Unitful.jl/issues/96).\n  - Improve symbol resolution in `u_str` macro [#98](https://github.com/JuliaPhysics/Unitful.jl/pull/98).\n  - More work is done inside the `u_str` macro, such that the macro returns units, dimensions,\n    numbers (quantities), or tuples rather than expressions.\n- v0.2.6\n  - Fix and close [#52](https://github.com/JuliaPhysics/Unitful.jl/issues/52).\n  - Implement `Base.rtoldefault` for Quantity types\n    (needed for AxisArrays [#52](https://github.com/JuliaArrays/AxisArrays.jl/pull/52)).\n- v0.2.5\n  - Fix and close [#79](https://github.com/JuliaPhysics/Unitful.jl/issues/79).\n  - Add support for `round(T, ::DimensionlessQuantity)` where `T <: Integer`\n    (also `floor`, `ceil`, `trunc`) [#90](https://github.com/JuliaPhysics/Unitful.jl/pull/90).\n- v0.2.4\n  - Bug fix: avoid four-argument `promote_type`\n  - Bug fix: define method for `*(::Base.TwicePrecision, ::Quantity)`\n  - Bug fix: definition of Bohr magneton had `e` instead of `q`\n- v0.2.3\n  - Dimensionful quantities are no longer accepted for `floor`, `ceil`, `trunc`, `round`,\n    `isinteger`. The choice of units can yield physically different results.\n    The functions are defined for dimensionless quantities, and return unitless numbers.\n    Closes [#78](https://github.com/JuliaPhysics/Unitful.jl/issues/78).\n  - Added `gn`, a constant quantity for the gravitational acceleration on earth\n    [#75](https://github.com/JuliaPhysics/Unitful.jl/pull/75).\n  - Added `ge`, the gravitational acceleration on earth as a unit\n    [#75](https://github.com/JuliaPhysics/Unitful.jl/pull/75).\n  - Added `lbf`, pounds-force unit\n    [#75](https://github.com/JuliaPhysics/Unitful.jl/pull/75).\n- v0.2.2\n  - Fixed a bug in promotion involving `ContextUnits` where the promotion context might\n    not be properly retained.\n- v0.2.1\n  - Fixed `isapprox` bug [#74](https://github.com/JuliaPhysics/Unitful.jl/pull/74).\n  - Added `DimensionlessQuantity` methods for `exp`, `exp10`, `exp2`, `expm1`, `log1p`,\n    `log2` [#71](https://github.com/JuliaPhysics/Unitful.jl/pull/71).\n- v0.2.0\n  - `Units{N,D}` is now an abstract type. Different concrete types for units give different\n   behavior under conversion and promotion. The currently implemented concrete types are:\n    - `FreeUnits{N,D}`: these give the typical behavior from prior versions of Unitful.\n      Units defined in Unitful.jl and reachable by the `u_str` macro are all `FreeUnits`.\n    - `ContextUnits{N,D,P}`, where P is some type `FreeUnits{M,D}`: these enable\n      context-specific promotion rules, e.g. if units are defined in different packages.\n    - `FixedUnits{N,D}`: these inhibit automatic conversion of quantities with different units.\n  - `LengthUnit`, `EnergyUnit`, etc. are renamed to `LengthUnits`, `EnergyUnits`, etc. for\n    consistency (they are related more to `Units` objects than `Unit` objects). You can\n    still use the old names for now, but please switch over to using `...Units` instead\n    of `...Unit` in this release as the old names will be removed in a future release.\n  - `c` is now a unit, to permit converting mass into `MeV/c^2`, for example. `c0` is\n    still a quantity equal to the speed of light in vacuum, in units of `m/s`\n    [#67](https://github.com/JuliaPhysics/Unitful.jl/issues/67).\n- v0.1.5\n  - Patch for Julia PR [#20889](https://github.com/JuliaLang/julia/pull/20889), which\n    changes how lowering is done for exponentiation of integer literals.\n  - Bug fix to enable registering Main as a module for `u_str` (fixes\n    [#61](https://github.com/JuliaPhysics/Unitful.jl/issues/61)).\n  - Implement readable message for `DimensionError`\n    [#62](https://github.com/JuliaPhysics/Unitful.jl/pull/62).\n- v0.1.4\n  - Critical bug fix owing to `mod_fast` changes.\n- v0.1.3\n  - Fix symmetry of `==` [#56](https://github.com/JuliaPhysics/Unitful.jl/issues/56).\n  - Using `@refunit` will implicitly specify the ref. unit as the default for promotion.\n    This will not change behavior for most people; it just ensures promotion won't\n    fail for quantities with user-defined dimensions.\n  - Remove `mod_fast` in anticipation of Julia PR [#20859](https://github.com/JuliaLang/julia/pull/20859).\n  - Allow tolerance args for `isapprox` [#57](https://github.com/JuliaPhysics/Unitful.jl/pull/57)\n- v0.1.2\n  - On Julia 0.6, exponentiation by a literal is now type stable for integers.\n- v0.1.1\n  - Fixed a macro hygiene issue that prevented `@dimension` and `@derived_dimension`\n   from working properly if Compat was not imported in the calling namespace.\n- v0.1.0\n  - Julia 0.6 compatibility.\n  - On Julia 0.6, exponentiation by a literal is now type stable for\n    common integer powers: -3, -2, -1, 0, 1, 2, 3.\n  - Added missing methods for dot operators `.<` and `.<=` (Julia 0.5, fix\n    [#55](https://github.com/JuliaPhysics/Unitful.jl/issues/55)).\n  - Fix [#45](https://github.com/JuliaPhysics/Unitful.jl/issues/45). Ranges should\n    work as expected on Julia 0.6. On Julia 0.5, [Ranges.jl](https://github.com/JuliaArrays/Ranges.jl)\n    is used to make ranges work as well as possible given limitations in Base.\n  - Fix [#33](https://github.com/JuliaPhysics/Unitful.jl/issues/33),\n    [#42](https://github.com/JuliaPhysics/Unitful.jl/issues/42),\n    and [#50](https://github.com/JuliaPhysics/Unitful.jl/issues/50).\n    `deps/Defaults.jl` is dead. Long live `deps/Defaults.jl`. To define your own\n    units, dimensions, and so on, you should now put them in a module, or ideally\n    a package so that others can use the definitions too. You can override default\n    promotion rules immediately after loading Unitful and dependent packages; this\n    will generate method overwrite warnings on Julia 0.5 but not on 0.6.\n  - `@u_str` macro has been improved. It can now traverse separate unit packages,\n    as well as return tuples of `Units` objects.\n  - `@preferunit` has been replaced with a function `preferunits`.\n  - Added some methods for `ustrip`.\n  - Implement `typemin`, `typemax`, `cbrt` for `Quantity`s.\n  - Added matrix inversion for `StridedMatrix{T<:Quantity}`.\n  - Added `istriu`, `istril` for `AbstractMatrix{T<:Quantity}`.\n  - The `Unitful.SIUnits` module has been renamed to `Unitful.DefaultSymbols`.\n  - Add `lb`, `oz`, `dr`, `gr` to Unitful (international Avoirdupois mass units).\n- v0.0.4\n  - Be aware, breaking changes to `deps/Defaults.jl` caused by some of the following!\n  - Fix [#40](https://github.com/JuliaPhysics/Unitful.jl/issues/40).\n  - Fix [#30](https://github.com/JuliaPhysics/Unitful.jl/issues/30).\n  - Support relevant `@fastmath` operations for `Quantity`s.\n  - Implement `fma`, `atan2` for `Quantity`s.\n  - Implement `cis` for dimensionless `Quantity`s.\n  - Removed `DimensionedUnits` and `DimensionedQuantity` abstract types.\n    They were of dubious utility, and this change shortened the promotion code\n    considerably. More importantly, this change has made it possible to write\n    methods like the following, without method ambiguities:\n    `uconvert(e::EnergyUnit, f::Frequency) = uconvert(e, u\"h\"*f)`.\n  - Promotion wraps usual `Number` types in dimensionless, unitless `Quantity`\n    types when promoted together with dimensionful `Quantity`s.\n    With `Quantity`s it is not always possible to promote to a common\n    concrete type, but this way we can at least ensure that the numeric backing\n    types are all promoted: (`promote(1.0u\"m\", 1u\"N\"//2, 0x08) == (1.0 m,0.5 N,8.0)`,\n    where `8.0` is actually a dimensionless, unitless `Quantity`).\n    The usual outer constructor for `Quantity`s (`Quantity(val::T, unit)`)\n    continues to return a number of type `T` if the unit is `NoUnits`,\n    since most of the time the user would prefer a `Number` type from base rather\n    than a dimensionless, unitless quantity.\n  - Add more units to defaults: `bar` (bar), `Torr` (torr), `atm` (atmosphere),\n    `l` or `L` (liter; both symbols accepted). You will need to delete\n    `deps/Defaults.jl` in the Unitful package directory to get the new units.\n  - Two character encodings for `μ` in SI prefixes are now generated automatically\n    (some logic moved out of defaults).\n  - Moved definition of `sin`, `cos`, `tan`, `sec`, `csc`, `cot` out of\n    `deps/build.jl` and into `src/Unitful.jl`.\n- v0.0.3\n  - Bug fix: `uconvert(°C, 0x01°C)` no longer disturbs the numeric type\n  - Allow μ-prefixed units to be typed with option-m on a Mac, in addition to\n    using Unicode. Previously only `μm` could be typed this way.\n  - Include a `baremodule` called `SIUnits` in the factory defaults. You can\n    now do `using Unitful.SIUnits` to bring all of the SI units into the calling\n    namespace.\n  - Added remaining SI units to the factory defaults: `sr` (steradian), `lm`\n    (luminous flux), `lx` (illuminance), `Bq` (becquerel), `Gy` (gray),\n    `Sv` (sievert), `kat` (katal).\n  - Simplify array creation, as in `[1, 2]u\"km\"` [#29](https://github.com/JuliaPhysics/Unitful.jl/pull/29)\n  - Support multiplying ranges by units, as in `(1:3)*mm` [#28](https://github.com/JuliaPhysics/Unitful.jl/pull/28)\n  - Bug fix [#26](https://github.com/JuliaPhysics/Unitful.jl/issues/26)\n  - Promoting `Quantity`s with different dimensions now returns quantities with\n    the same numeric backing type, e.g. `Quantity{Float64}`. Ideally, this would\n    also be true if you mixed unitless and unitful numbers during promotion, but\n    that is not yet the case. See [#24](https://github.com/JuliaPhysics/Unitful.jl/issues/24)\n    for motivation.\n- v0.0.2\n  - Bug fixes (`[1.0m, 2.0m] ./ 3` would throw a `Unitful.DimensionError()`).\n    Promotion still isn't perfect, but it is hard for me to see what `@inferred`\n    errors are real until https://github.com/JuliaLang/julia/issues/18465 is resolved.\n  - Made units callable for unit conversion: `u\"cm\"(1u\"m\") == 100u\"cm\"//1`.\n    Note that `Units` objects have no fields, so this is totally unambiguous.\n    Moreover, we have convenient syntax for unit conversion by function chaining:\n    `1u\"m\" |> u\"cm\" == 100u\"cm\"//1`. Note that `uconvert` will remain supported.\n- v0.0.1 - Initial release\n"
  },
  {
    "path": "Project.toml",
    "content": "name = \"Unitful\"\nuuid = \"1986cc42-f94f-5a68-af5c-568840ba703d\"\nversion = \"1.28.0\"\n\n[deps]\nConstructionBase = \"187b0558-2788-49d3-abe0-74a17ed4e7c9\"\nDates = \"ade2ca70-3891-5945-98fb-dc099432e06a\"\nInverseFunctions = \"3587e190-3f89-42d0-90ee-14403ec27112\"\nLinearAlgebra = \"37e2e46d-f89d-539d-b4ee-838fcccc9c8e\"\nRandom = \"9a3f8284-a2c9-5f02-9a11-845980a1fd5c\"\n\n[weakdeps]\nConstructionBase = \"187b0558-2788-49d3-abe0-74a17ed4e7c9\"\nForwardDiff = \"f6369f11-7733-5829-9624-2563aa707210\"\nInverseFunctions = \"3587e190-3f89-42d0-90ee-14403ec27112\"\nLatexify = \"23fbe1c1-3f47-55db-b15f-69d7ec21a316\"\nLaTeXStrings = \"b964fa9f-0449-5b57-a5c2-d3ea65f4040f\"\nNaNMath = \"77ba4419-2d1f-58cd-9bb1-8ffee604a2e3\"\nPrintf = \"de0858da-6303-5e67-8744-51eddeeeb8d7\"\n\n[extensions]\nConstructionBaseUnitfulExt = \"ConstructionBase\"\nForwardDiffExt = \"ForwardDiff\"\nInverseFunctionsUnitfulExt = \"InverseFunctions\"\nLatexifyExt = [\"Latexify\", \"LaTeXStrings\"]\nNaNMathExt = \"NaNMath\"\nPrintfExt = \"Printf\"\n\n[compat]\nAqua = \"0.8\"\nConstructionBase = \"1\"\nDates = \"<0.0.1, 1\"\nForwardDiff = \"0.10, 1\"\nInverseFunctions = \"0.1\"\nLaTeXStrings = \"1.2.0\"\nLatexify = \"0.16.8\"\nLinearAlgebra = \"<0.0.1, 1\"\nNaNMath = \"1\"\nPrintf = \"<0.0.1, 1\"\nREPL = \"<0.0.1, 1\"\nRandom = \"<0.0.1, 1\"\nTest = \"<0.0.1, 1\"\njulia = \"1.6\"\n\n[extras]\nAqua = \"4c88cf16-eb10-579e-8560-4a9242c79595\"\nConstructionBase = \"187b0558-2788-49d3-abe0-74a17ed4e7c9\"\nForwardDiff = \"f6369f11-7733-5829-9624-2563aa707210\"\nInverseFunctions = \"3587e190-3f89-42d0-90ee-14403ec27112\"\nLatexify = \"23fbe1c1-3f47-55db-b15f-69d7ec21a316\"\nLaTeXStrings = \"b964fa9f-0449-5b57-a5c2-d3ea65f4040f\"\nLinearAlgebra = \"37e2e46d-f89d-539d-b4ee-838fcccc9c8e\"\nNaNMath = \"77ba4419-2d1f-58cd-9bb1-8ffee604a2e3\"\nPrintf = \"de0858da-6303-5e67-8744-51eddeeeb8d7\"\nREPL = \"3fa0cd96-eef1-5676-8a61-b3b8758bbffb\"\nRandom = \"9a3f8284-a2c9-5f02-9a11-845980a1fd5c\"\nTest = \"8dfed614-e22c-5e08-85e1-65c5234f0b40\"\n\n[targets]\ntest = [\"Aqua\", \"ConstructionBase\", \"ForwardDiff\", \"InverseFunctions\", \"Latexify\", \"LaTeXStrings\", \"LinearAlgebra\", \"NaNMath\", \"Test\", \"Random\", \"REPL\", \"Printf\"]\n"
  },
  {
    "path": "README.md",
    "content": "[![CI](https://github.com/JuliaPhysics/Unitful.jl/workflows/CI/badge.svg)](https://github.com/JuliaPhysics/Unitful.jl/actions?query=workflow%3ACI)\n[![Coverage Status](https://coveralls.io/repos/github/JuliaPhysics/Unitful.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaPhysics/Unitful.jl?branch=master)\n[![codecov.io](https://codecov.io/github/JuliaPhysics/Unitful.jl/coverage.svg?branch=master)](https://codecov.io/github/JuliaPhysics/Unitful.jl?branch=master)\n\n\n\n# Unitful.jl\n\nUnitful is a Julia package for physical units. We want to support not only\nSI units but also any other unit system. We also want to minimize or in some\ncases eliminate the run-time penalty of units. There should be facilities\nfor dimensional analysis. All of this should integrate easily with the usual\nmathematical operations and collections that are found in Julia base.\n\n### Documentation: [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaPhysics.github.io/Unitful.jl/stable) [![](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaPhysics.github.io/Unitful.jl/dev)\n\n\n## Other packages in the Unitful family\n\n### Units packages\n\n- [UnitfulUS.jl](https://github.com/PainterQubits/UnitfulUS.jl): U.S. customary units. Serves as an example for how to implement a units\n  package.\n- [UnitfulAstro.jl](https://github.com/mweastwood/UnitfulAstro.jl): Astronomical units.\n- [UnitfulAngles.jl](https://github.com/yakir12/UnitfulAngles.jl): More angular units, additional trigonometric functionalities, and clock-angle conversion.\n- [UnitfulAtomic.jl](https://github.com/sostock/UnitfulAtomic.jl): Easy conversion from and to atomic units.\n- [PowerSystemsUnits.jl](https://github.com/invenia/PowerSystemsUnits.jl): Common units for dealing with power systems.\n- [UnitfulMoles.jl](https://github.com/rafaqz/UnitfulMoles.jl) for defining mol units of chemical elements and compounds.\n\n### Feature additions\n\n- [UnitfulEquivalences.jl](https://github.com/sostock/UnitfulEquivalences.jl): Enables conversion between equivalent quantities of different dimensions, e.g. between energy and wavelength of a photon.\n- [UnitfulParsableString.jl](https://github.com/michikawa07/UnitfulParsableString.jl): Add a `Base.string` method that converts quantities and units to parsable strings.\n- [UnitfulBuckinghamPi.jl](https://github.com/rmsrosa/UnitfulBuckinghamPi.jl): Solves for the adimensional Pi groups in a list of Unitful parameters, according to the Buckingham-Pi Theorem.\n- [NaturallyUnitful.jl](https://github.com/MasonProtter/NaturallyUnitful.jl): Convert to and from natural units in physics.\n- [UnitfulChainRules.jl](https://github.com/SBuercklin/UnitfulChainRules.jl): Enables use of Unitful quantities with [ChainRules.jl](https://github.com/JuliaDiff/ChainRules.jl)-compatible autodifferentiation systems.\n- [DimensionfulAngles.jl](https://github.com/JuliaOceanWaves/DimensionfulAngles.jl): Adds angle as a dimension. This allows dispatching on angles and derived quantities.\n- [Dimensionless.jl](https://github.com/martinkosch/Dimensionless.jl): Contains tools to switch between dimensional bases, conduct dimensional analysis and solve similitude problems.\n- [UnitfulRecipes.jl](https://github.com/jw3126/UnitfulRecipes.jl) (deprecated): Adds automatic labels and supports plot axes with units for [Plots.jl](https://github.com/JuliaPlots/Plots.jl). (UnitfulRecipes.jl is now included in Plots.jl.)\n- [UnitfulLatexify.jl](https://github.com/gustaphe/UnitfulLatexify.jl) (deprecated): Pretty print units and quantities in LaTeX format. (This package is now an extension to Unitful, so that loading both Unitful and [Latexify.jl](https://github.com/korsbo/Latexify.jl) loads this functionality.)\n\n\n## Related packages\n\nUnitful was inspired by:\n\n- [SIUnits.jl](https://github.com/keno/SIUnits.jl)\n- [EngUnits.jl](https://github.com/dhoegh/EngUnits.jl)\n- [Units.jl](https://github.com/timholy/Units.jl)\n"
  },
  {
    "path": "docs/Project.toml",
    "content": "[deps]\nDates = \"ade2ca70-3891-5945-98fb-dc099432e06a\"\nDocumenter = \"e30172f5-a6a5-5a46-863b-614d45cd2de4\"\nFontconfig = \"186bb1d3-e1f7-5a2c-a377-96d770f13627\"\nInverseFunctions = \"3587e190-3f89-42d0-90ee-14403ec27112\"\nLaTeXStrings = \"b964fa9f-0449-5b57-a5c2-d3ea65f4040f\"\nLatexify = \"23fbe1c1-3f47-55db-b15f-69d7ec21a316\"\nMarkdown = \"d6f4376e-aef5-505a-96c1-9c027394607a\"\nPlots = \"91a5bcdd-55d7-5caf-9e0b-520d859cae80\"\nUnitful = \"1986cc42-f94f-5a68-af5c-568840ba703d\"\ntectonic_jll = \"d7dd28d6-a5e6-559c-9131-7eb760cdacc5\"\n\n[sources]\nUnitful = {path = \"..\"}\n\n[compat]\nDocumenter = \"1\"\nLatexify = \"0.16.10\"\nPlots = \"1\"\nFontconfig = \"0.4\"\n"
  },
  {
    "path": "docs/generate_latex_images.jl",
    "content": "using LaTeXStrings, Unitful, Latexify\nimport tectonic_jll # needed for lightweight LaTeX render\nusing Fontconfig: format, match, Pattern\n\n# Since the docs can get built on different systems, we need to find a locally installed \n# monospaced font that has enough Unicode coverage to handle π\nmonofont = format(match(Pattern(spacing=100, charset=\"3c0\")), \"%{family}\")\n\ncommands = [\n    :(latexify(612.2u\"nm\")),\n    :(latexify(u\"kg*m/s^2\")),\n    :(latexify(612.2u\"nm\"; fmt=SiunitxNumberFormatter())),\n    :(latexify(u\"kg*m/s^2\"; fmt=SiunitxNumberFormatter())),\n    :(latexify(612.2u\"nm\"; fmt=SiunitxNumberFormatter(; simple=true))),\n    :(latexify(u\"kg*m/s^2\"; fmt=SiunitxNumberFormatter(; simple=true))),\n    :(latexify((1, 2, 4) .* u\"m\"; fmt=SiunitxNumberFormatter())),\n]\ntab1 = map(commands) do command\n    LaTeXString.([\n        \"\\\\verb+$(string(command))+\",\n        \"\\\\verb+$(eval(command))+\",\n        \"$(eval(command)) \",\n    ])\nend\nltab1 = latextabular(tab1, adjustment=:l, transpose=true, latex=false, booktabs=true, \n    head=[\"julia\", \"\\\\LaTeX\", \"Result\"])\n# Setting an explicit white background color results in transparent PDF, so go offwhite.\nltab1 = LaTeXString(\"\"\"\n    \\\\setmonofont{$monofont}\n    \\\\definecolor{offwhite}{rgb}{0.999,0.999,0.999}\n    \\\\pagecolor{offwhite}\n    \\\\color{black}\n\"\"\" * ltab1)\n\nrender(ltab1, MIME(\"image/png\"); use_tectonic=true, open=false,\n    name=(@__DIR__)*\"/src/assets/latex-examples\", \n    packages=[\"booktabs\", \"color\", \"siunitx\", \"fontspec\"], \n    documentclass=(\"standalone\"))\n\nfunctions = [\n    x -> \"\\\\verb+$(string(x))+\",\n    x -> latexify(x),\n    x -> latexify(x; fmt=SiunitxNumberFormatter()),\n    x -> latexify(x; fmt=SiunitxNumberFormatter(; simple=true)),\n]\nallunits = begin\n    uparse.([\n        \"nH*m/Hz\",\n        \"m\",\n        \"s\",\n        \"A\",\n        \"K\",\n        \"cd\",\n        \"g\",\n        \"mol\",\n        \"sr\",\n        \"rad\",\n        \"°\",\n        \"Hz\",\n        \"N\",\n        \"Pa\",\n        \"J\",\n        \"W\",\n        \"C\",\n        \"V\",\n        \"S\",\n        \"F\",\n        \"H\",\n        \"T\",\n        \"Wb\",\n        \"lm\",\n        \"lx\",\n        \"Bq\",\n        \"Gy\",\n        \"Sv\",\n        \"kat\",\n        #\"percent\", # Messes with comments\n        # \"permille\", # Undefined in all formats\n        # \"pertenthousand\", # Undefined in all formats (butchered)\n        \"°C\",\n        \"°F\", # No longer in siunitx\n        \"minute\",\n        \"hr\",\n        \"d\",\n        \"wk\", # Undefined in siunitx\n        \"yr\", # Undefined in siunitx\n        \"rps\", # Undefined in siunitx\n        \"rpm\", # Undefined in siunitx\n        \"a\", # Undefined in siunitx\n        \"b\",\n        \"L\",\n        \"M\", # Undefined in siunitx\n        \"eV\",\n        \"Hz2π\", # Butchered by encoding\n        \"bar\",\n        \"atm\", # Undefined in siunitx\n        \"Torr\", # Undefined in siunitx\n        \"c\", # Undefined in siunitx\n        \"u\", # Undefined in siunitx\n        \"ge\", # Undefined in siunitx\n        \"Gal\", # Undefined in siunitx\n        \"dyn\", # Undefined in siunitx\n        \"erg\", # Undefined in siunitx\n        \"Ba\", # Undefined in siunitx\n        \"P\", # Undefined in siunitx\n        \"St\", # Undefined in siunitx\n        #\"Gauss\", # errors in testing, maybe from Unitful.jl's dev branch?\n        #\"Oe\", # errors in testing, maybe from Unitful.jl's dev branch?\n        #\"Mx\", # errors in testing, maybe from Unitful.jl's dev branch?\n        \"inch\", # Undefined in siunitx\n        \"mil\", # Undefined in siunitx\n        \"ft\", # Undefined in siunitx\n        \"yd\", # Undefined in siunitx\n        \"mi\", # Undefined in siunitx\n        \"angstrom\", # Undefined in mathrm,siunitxsimple\n        \"ac\", # Undefined in siunitx\n        \"Ra\", # Undefined in siunitx\n        \"lb\", # Undefined in siunitx\n        \"oz\", # Undefined in siunitx\n        \"slug\", # Undefined in siunitx\n        \"dr\", # Undefined in siunitx\n        \"gr\", # Undefined in siunitx\n        \"lbf\", # Undefined in siunitx\n        \"cal\", # Undefined in siunitx\n        \"btu\", # Undefined in siunitx\n        \"psi\", # Undefined in siunitx\n        #\"dBHz\", # Cannot *yet* be latexified.\n        #\"dBm\", # Cannot *yet* be latexified.\n        #\"dBV\", # Cannot *yet* be latexified.\n        #\"dBu\", # Cannot *yet* be latexified.\n        #\"dBμV\", # Cannot *yet* be latexified.\n        #\"dBSPL\", # Cannot *yet* be latexified.\n        #\"dBFS\", # Cannot *yet* be latexified.\n        #\"dBΩ\", # Cannot *yet* be latexified.\n        #\"dBS\", # Cannot *yet* be latexified.\n    ])\nend\n\ntab2 = map(allunits) do unit\n    [LaTeXString(f(unit)) for f in functions]\nend\nltab2 = latextabular(tab2, adjustment=:l, transpose=true, latex=false, booktabs=true, \n    head=[\"Name\", \"Default number formatter\", \"\\\\verb+SiunitxNumberFormatter()+\", \"\\\\verb+SiunitxNumberFormatter(;simple=true)+\"])\n# Set background to not-quite-white so it doesn't get treated as transparent\nltab2 = LaTeXString(\n    \"\"\"\n    \\\\setmonofont{$monofont}\n    \\\\definecolor{offwhite}{rgb}{0.999,0.999,0.999}\n    \\\\pagecolor{offwhite}\n    \\\\color{black}\n    \"\"\" * ltab2)\n\nrender(ltab2, MIME(\"image/png\"); use_tectonic=true, open=false,\n    tectonic_flags=`-Z continue-on-errors`,\n    name=(@__DIR__)*\"/src/assets/latex-allunits\", \n    packages=[\"booktabs\", \"color\", \"siunitx\", \"fontspec\"], \n    documentclass=(\"standalone\"))\n"
  },
  {
    "path": "docs/make.jl",
    "content": "using Documenter, Unitful, Dates\n\n@info \"Generating latex images for documentation\"\ninclude(\"generate_latex_images.jl\")\n\nDocMeta.setdocmeta!(Unitful, :DocTestSetup, :(using Unitful))\nwithenv(\"UNITFUL_FANCY_EXPONENTS\" => \"false\") do\n    makedocs(\n        sitename = \"Unitful.jl\",\n        format = Documenter.HTML(prettyurls = get(ENV, \"CI\", nothing) == \"true\"),\n        warnonly = [:missing_docs],\n        modules = [Unitful],\n        workdir = joinpath(@__DIR__, \"..\"),\n        pages = [\n            \"Home\" => \"index.md\"\n            \"Highlighted features\" => \"highlights.md\"\n            \"Types\" => \"types.md\"\n            \"Defining new units\" => \"newunits.md\"\n            \"Conversion/promotion\" => \"conversion.md\"\n            \"Manipulating units\" => \"manipulations.md\"\n            \"How units are displayed\" => \"display.md\"\n            \"Logarithmic scales\" => \"logarithm.md\"\n            \"Temperature scales\" => \"temperature.md\"\n            \"Interoperability with `Dates`\" => \"dates.md\"\n            \"Latexifying units\" => \"latexify.md\"\n            \"Extending Unitful\" => \"extending.md\"\n            \"Troubleshooting\" => \"trouble.md\"\n            \"Pre-defined dimensions, units, and constants\" => \"defaultunits.md\"\n            \"License\" => \"LICENSE.md\"\n        ]\n    )\nend\n\ndeploydocs(repo = \"github.com/JuliaPhysics/Unitful.jl.git\")\n"
  },
  {
    "path": "docs/src/LICENSE.md",
    "content": "# License\n\n```@eval\nusing Markdown\nopen(Markdown.parse, \"LICENSE.md\")\n```\n"
  },
  {
    "path": "docs/src/conversion.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Conversion/promotion\n\n## Converting between units\n\nSince `convert` in Julia already means something specific (conversion between\nJulia types), we define [`uconvert`](@ref) for conversion between units. Typically\nthis will also involve a conversion between types, but this function takes care\nof figuring out which type is appropriate for representing the desired units.\n\nExact conversions between units are respected where possible. If rational\narithmetic would result in an overflow, then floating-point conversion should\nproceed. Use of floating-point numbers inhibits exact conversion.\n\n```@docs\nuconvert\n```\n\nSince objects are callable, we can also make [`Unitful.Units`](@ref) callable\nwith a `Number` as an argument, for a unit conversion shorthand:\n\n```jldoctest\njulia> u\"cm\"(1u\"m\")\n100 cm\n```\n\nThis syntax is a little confusing, but becomes appealing with the function\nchaining operator `|>`:\n\n```jldoctest\njulia> 1u\"m\" |> u\"cm\"\n100 cm\n```\n\nNote that since [`Unitful.Units`](@ref) objects have no fields, we don't have\nto worry about ambiguity with constructor calls. This way of converting units\nresults in behavior identical to calling [`uconvert`](@ref).\n\n### Dimensionless quantities\n\nFor dimensionless quantities, `uconvert` can be used with the [`NoUnits`](@ref) unit to\nstrip the units without losing power-of-ten information:\n\n```jldoctest\njulia> uconvert(NoUnits, 1.0u\"μm/m\")\n1.0e-6\n\njulia> uconvert(NoUnits, 1.0u\"m\")\nERROR: DimensionError:  and m are not dimensionally compatible.\n```\n\n```@docs\nUnitful.NoUnits\n```\n\nYou can also directly convert to a subtype of `Real` or `Complex`:\n\n```jldoctest\njulia> convert(Float64, 1.0u\"μm/m\")\n1.0e-6\n```\n\n## Basic promotion mechanisms\n\nWe decide the result units for addition and subtraction operations based on looking at the\ntypes only. We can't take runtime values into account without compromising runtime\nperformance.\n\nIf two quantities with the same units are added or subtracted, then the result units\nwill be the same. If two quantities with differing units (but same dimension) are added\nor subtracted, then the result units will be specified by promotion.\n\n### Promotion rules for specific dimensions\n\nYou can specify the result units for promoting quantities of a specific dimension\nonce at the start of a Julia session. For example, you can specify that when promoting\ntwo quantities with different energy units, the resulting quantities should be in\n`g*cm^2/s^2`. This is accomplished by defining a `Unitful.promote_unit` method for the units\nthemselves. Here's an example.\n\n```jldoctest\njulia> using Unitful\n\njulia> Unitful.promote_unit(::S, ::T) where {S<:Unitful.EnergyUnits, T<:Unitful.EnergyUnits} = u\"g*cm^2/s^2\"\n\njulia> promote(2.0u\"J\", 1.0u\"kg*m^2/s^2\")\n(2.0e7 g cm^2 s^-2, 1.0e7 g cm^2 s^-2)\n\njulia> Unitful.promote_unit(::S, ::T) where {S<:Unitful.EnergyUnits, T<:Unitful.EnergyUnits} = u\"J\"\n\njulia> promote(2.0u\"J\", 1.0u\"kg*m^2/s^2\")\n(2.0 J, 1.0 J)\n```\n\nIf you're wondering where `Unitful.EnergyUnits` comes from, it is defined in\n`src/pkgdefaults.jl` by the [`@derived_dimension`](@ref) macro. Similarly,\nthe calls to the [`@dimension`](@ref) macro define `Unitful.LengthUnits`,\n`Unitful.MassUnits`, etc. None of these are exported.\n\nExisting users of Unitful may want to call [`Unitful.promote_to_derived`](@ref)\nafter Unitful loads to give similar behavior to Unitful 0.0.4 and below. It is\nnot called by default.\n\n```@docs\nUnitful.promote_to_derived\n```\n\n### Fallback promotion rules\n\nThe [`Unitful.preferunits`](@ref) function is used to designate fallback\npreferred units for each pure dimension for promotion. Such a fallback is\nrequired because you need some generic logic to take over when manipulating\nquantities with arbitrary dimensions.\n\nThe default behavior is to promote to a combination of the base SI units, i.e.\na quantity of dimension `𝐌*𝐋^2/(𝐓^2*𝚯)` would be converted to `kg*m^2/(s^2*K)`:\n\n```jldoctest\njulia> promote(1.0u\"J/K\", 1.0u\"g*cm^2/s^2/K\")\n(1.0 kg m^2 K^-1 s^-2, 1.0e-7 kg m^2 K^-1 s^-2)\n```\n\nYou can however override this behavior by calling [`Unitful.preferunits`](@ref)\nat the start of a Julia session, specifically *before* [`Unitful.upreferred`](@ref)\n*has been called or quantities have been promoted*.\n\n```@docs\nUnitful.preferunits\nUnitful.upreferred\n```\n\n### Array promotion\n\nArrays are typed with as much specificity as possible upon creation. consider\nthe following three cases:\n\n```jldoctest\njulia> [1.0u\"m\", 2.0u\"m\"]\n2-element Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}:\n 1.0 m\n 2.0 m\n\njulia> [1.0u\"m\", 2.0u\"cm\"]\n2-element Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}:\n 1.0 m\n 0.02 m\n\njulia> [1.0u\"m\", 2.0]\n2-element Vector{Quantity{Float64}}:\n 1.0 m\n 2.0\n```\n\nIn the first case, an array with a concrete type is created. Good\nperformance should be attainable. The second case invokes promotion so that an\narray of concrete type can be created. The third case falls back to an abstract\ntype, which cannot be stored efficiently and will incur a performance penalty.\nAn additional benefit of having a concrete type is that we can dispatch on the\ndimensions of the array's elements:\n\n```jldoctest\njulia> f(x::AbstractArray{T}) where {T<:Unitful.Length} = sum(x)\nf (generic function with 1 method)\n\njulia> f([1.0u\"m\", 2.0u\"cm\"])\n1.02 m\n\njulia> f([1.0u\"g\", 2.0u\"cm\"])\nERROR: MethodError: no method matching f(::Vector{Quantity{Float64}})\n[...]\n```\n\n## Advanced promotion mechanisms\n\nThere are some new types as of Unitful.jl v0.2.0 that enable some fairly sophisticated\npromotion logic. Three concrete subtypes of [`Unitful.Units{N,D,A}`](@ref) are defined:\n[`Unitful.FreeUnits{N,D,A}`](@ref), [`Unitful.ContextUnits{N,D,P,A}`](@ref), and\n[`Unitful.FixedUnits{N,D,A}`](@ref).\n\nUnits defined in the Unitful.jl package itself are all `Unitful.FreeUnits{N,D,A}` objects.\nThe \"free\" in `FreeUnits` indicates that the object carries no information on its own about\nhow it should respond during promotion. Other code in Unitful dictates that by default,\nquantities should promote to SI units. `FreeUnits` use the promotion mechanisms described\nin the above section, [Basic promotion mechanisms](@ref). They used to be called `Units`\nin prior versions of Unitful.\n\n### ContextUnits\n\nSometimes, a package may want to default to a particular behavior for promotion, in the\npresence of other packages that may require differing default behaviors. An example would be\na CAD package for nanoscale device design: it makes more sense to promote to nanometers or\nmicrons than to meters. For this purpose we define `Unitful.ContextUnits{N,D,P,A}`. The `P` in\nthis type signature should be some type `Unitful.FreeUnits{M,D,B}` (the dimensions must be the\nsame). We refer to this as the \"context.\" `ContextUnits` may be easily instantiated by e.g.\n`ContextUnits(nm, μm)` for a `nm` unit that will promote to `μm`. Here's an example:\n\n```jldoctest\njulia> μm = Unitful.ContextUnits(u\"μm\", u\"μm\")\nμm\n\njulia> nm = Unitful.ContextUnits(u\"nm\", u\"μm\")\nnm\n\njulia> 1.0μm + 1.0nm\n1.001 μm\n```\n\nIf the context does not agree, then we fall back to `FreeUnits`:\n\n```jldoctest\njulia> μm = Unitful.ContextUnits(u\"μm\", u\"μm\")\nμm\n\njulia> nm = Unitful.ContextUnits(u\"nm\", u\"cm\")\nnm\n\njulia> 1.0μm + 1.0nm\n1.001e-6 m\n```\n\nMultiplying a `ContextUnits` by a `FreeUnits` yields a\n`ContextUnits` object, with the preferred units for the additional dimensions being\ndetermined by calling [`Unitful.upreferred`](@ref) on the `FreeUnits` object:\n\n```jldoctest\njulia> mm = Unitful.ContextUnits(u\"mm\", u\"μm\")\nmm\n\njulia> isa(u\"g\", Unitful.FreeUnits)\ntrue\n\njulia> upreferred(u\"g\")\nkg\n\njulia> mm*u\"g\"\ng mm\n\njulia> isa(mm*u\"g\", Unitful.ContextUnits)\ntrue\n\njulia> upreferred(mm*u\"g\")\nkg μm\n```\n\n### FixedUnits\n\nSometimes, there may be times where it is required to disable automatic conversion between\nquantities with different units. For this purpose there are `Unitful.FixedUnits{N,D,A}`.\nTrying to add or compare two quantities with `FixedUnits` will throw an error, provided the\nunits are not the same. Note that you can still add/compare a quantity with `FixedUnits` to\na quantity with another kind of units; in that case, the result units (if applicable) are\ndetermined by the `FixedUnits`, overriding the preferred units from `ContextUnits` or\n`FreeUnits`. Multiplying `FixedUnits` with any other kind of units returns `FixedUnits`:\n\n```jldoctest\njulia> mm_fix = Unitful.FixedUnits(u\"mm\")\nmm\n\njulia> cm_fix = Unitful.FixedUnits(u\"cm\")\ncm\n\njulia> 1mm_fix+2mm_fix\n3 mm\n\njulia> 1mm_fix+2u\"cm\"  # u\"cm\" is a FreeUnits object.\n21 mm\n\njulia> 1mm_fix+2*Unitful.ContextUnits(u\"cm\", u\"cm\")\n21 mm\n\njulia> isa(mm_fix*u\"cm\", Unitful.FixedUnits)\ntrue\n\njulia> 1mm_fix+2cm_fix\nERROR: automatic conversion prohibited.\n[...]\n\njulia> 1mm_fix == 1mm_fix\ntrue\n\njulia> 1mm_fix == 0.1u\"cm\"\ntrue\n\njulia> 1mm_fix == 0.1cm_fix\nERROR: automatic conversion prohibited.\n[...]\n```\n\nMuch of this functionality is enabled by `promote_unit` definitions. These are not\nreadily extensible by the user at this point.\n\n```@docs\n    Unitful.promote_unit\n```\n\n## Unit cancellation\n\nFor multiplication and division, note that powers-of-ten prefixes are significant\nin unit cancellation. For instance, `mV/V` is not simplified, although `V/V` is.\nAlso, `N*m/J` is not simplified: there is currently no logic to decide\nwhether or not units on a dimensionless quantity seem \"intentional\" or not.\nIt is however possible to cancel units manually, by converting the dimensionless\nquantity to the [`NoUnits`](@ref) unit. This takes into account different SI-prefixes:\n```jldoctest\njulia> using Unitful\n\njulia> 1u\"kN*m\"/4u\"J\" |> NoUnits\n250.0\n```\n"
  },
  {
    "path": "docs/src/dates.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Interoperability with the `Dates` standard library\n\n[Julia's `Dates` standard library](https://docs.julialang.org/en/v1/stdlib/Dates/) provides data types for representing specific points in time `Date`/`DateTime` and differences between them, i.e., periods. Unitful provides methods for using period types from the `Dates` standard library together with `Quantity`s.\n\n## Support for `Dates.FixedPeriod`s\n\nThe `Dates.FixedPeriod` union type includes all `Dates.Period`s that represent a fixed period of time, i.e., `Dates.Week`, `Dates.Day`, `Dates.Hour`, `Dates.Minute`, `Dates.Second`, `Dates.Millisecond`, `Dates.Microsecond`, and `Dates.Nanosecond`. These types can be converted to `Quantity`s or used in place of them.\n\n!!! note\n    `Dates.Year` does not represent a fixed period and cannot be converted to a `Quantity`. While Unitful's `yr` unit is exactly equal to 365.25 days, a `Dates.Year` may contain 365 or 366 days.\n\nEach `FixedPeriod` is considered equivalent to a `Quantity`. For example, `Dates.Millisecond(5)` corresponds to the quantity `Int64(5)*u\"ms\"`. A `FixedPeriod` can be converted to the equivalent `Quantity` with a constructor:\n\n```@docs\nUnitful.Quantity(::Dates.FixedPeriod)\n```\n\nIn most respects, `FixedPeriod`s behave like their equivalent quantities. They can be converted to other units using `uconvert`, used in arithmetic operations with other quantities, and they have a `unit` and `dimension`:\n\n```jldoctest\njulia> using Dates: Hour\n\njulia> p = Hour(3)\n3 hours\n\njulia> uconvert(u\"s\", p)\n10800 s\n\njulia> p == 180u\"minute\"\ntrue\n\njulia> p < 1u\"d\"\ntrue\n\njulia> 5u\"s\" + p\n10805 s\n\njulia> 210u\"km\" / p\n70.0 km hr^-1\n\njulia> unit(p) === u\"hr\"\ntrue\n\njulia> dimension(p)\n𝐓\n```\n\nConversely, a `FixedPeriod` can be created from a quantity using the appropriate constructor, `convert`, or `round` methods. This will fail (i.e., throw an `InexactError`) if the resulting value cannot be represented as an `Int64`:\n\n```jldoctest\njulia> using Dates: Day, Hour, Millisecond\n\njulia> Millisecond(1.5u\"s\")\n1500 milliseconds\n\njulia> convert(Hour, 1u\"yr\")\n8766 hours\n\njulia> Day(1u\"yr\")\nERROR: InexactError: Int64(1461//4)\n[...]\n\njulia> round(Day, 1u\"yr\")\n365 days\n```\n\n## Support for `Dates.CompoundPeriod`s\n\nThe `Dates` standard library provides the `Dates.CompoundPeriod` type to represent sums of periods of different types:\n\n```@repl\nusing Dates: Day, Second\nDay(5) + Second(1)\ntypeof(ans)\n```\n\nUnitful provides facilities to work with `CompoundPeriod`s as long as they consist only of `FixedPeriod`s. Such `CompoundPeriod`s can be converted to `Quantity`s using `convert`, `uconvert`, or `round`:\n\n```@jldoctest\njulia> using Dates: Day, Second\n\njulia> p = Day(5) + Second(1)\n5 days, 1 second\n\njulia> uconvert(u\"s\", p)\n432001//1 s\n\njulia> convert(typeof(1.0u\"yr\"), p)\n0.01368928562374832 yr\n\njulia> round(u\"d\", p)\n5//1 d\n\njulia> q = Month(1) + Day(1)  # Month is not a fixed period\n1 month, 1 day\n\njulia> uconvert(u\"s\", q)\nERROR: MethodError: no method matching Quantity{Rational{Int64},𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}}(::Month)\n[...]\n```\n\nHowever, not all operations that are defined for `FixedPeriod`s support `CompoundPeriod`s as well.\nThe reason for that is that a `CompoundPeriod` does not correspond to a specific unit:\n\n```@jldoctest\njulia> p = Day(365) + Hour(6)\n365 days, 6 hours\n\njulia> unit(p)  # A CompoundPeriod does not have a corresponding unit ...\nERROR: MethodError: no method matching unit(::Dates.CompoundPeriod)\n[...]\n\njulia> dimension(p)  # ... but it does have a dimension\n𝐓\n\njulia> Quantity(p)  # As a result, there is no Quantity type associated with it ...\nERROR: MethodError: no method matching Quantity(::Int64)\n[...]\n\njulia> T = typeof(1.0u\"hr\"); T(p)  # ... but it can be converted to a concrete time quantity\n8766.0 hr\n```\n\nConsequently, any operation whose result would depend on the input unit is not supported by `CompoundPeriod`s. For example:\n\n* `+(::Quantity, ::CompoundPeriod)` and `+(::CompoundPeriod, ::Quantity)` error, since the unit of the result depends on the units of both arguments.\n* `div(::Quantity, ::CompoundPeriod)` and `div(::CompoundPeriod, ::Quantity)` work, since the result is a dimensionless number.\n* `mod(::CompoundPeriod, ::Quantity)` works, but `mod(::Quantity, ::CompoundPeriod)` does not, since the second argument determines the unit of the returned quantity.\n"
  },
  {
    "path": "docs/src/defaultunits.md",
    "content": "# Pre-defined units and сonstants\n\nIn the following, only non-prefixed units are listed. To get a more detailed information about a unit, and to get information about prefixed units, use `Julia` help, e.g.\n\n```\nhelp?> Unitful.kW\n  Unitful.kW\n\n  A prefixed unit, equal to 10^3 W.\n\n  Dimension: 𝐋² 𝐌 𝐓⁻³\n\n  See also: Unitful.W.\n```\n\nFor prefixes, see [below](#Metric-(SI)-Prefixes).\n\n\n## Base dimensions\n\n### Amount\n\n```@docs\nUnitful.𝐍\nUnitful.Amount\nUnitful.mol\n```\n\n### Current\n\n```@docs\nUnitful.𝐈\nUnitful.Current\nUnitful.A\n```\n\n### Length\n\n```@docs\nUnitful.𝐋\nUnitful.Length\nUnitful.angstrom\nUnitful.cm\nUnitful.fm\nUnitful.ft\nUnitful.inch\nUnitful.m\nUnitful.mi\nUnitful.mil\nUnitful.nm\nUnitful.yd\n```\n\n### Luminosity\n\n```@docs\nUnitful.𝐉\nUnitful.Luminosity\nUnitful.cd\nUnitful.lm\n```\n\n### Mass\n\n```@docs\nUnitful.𝐌\nUnitful.Mass\nUnitful.dr\nUnitful.g\nUnitful.gr\nUnitful.kg\nUnitful.lb\nUnitful.oz\nUnitful.slug\nUnitful.u\n```\n\n### Temperature\n\n```@docs\nUnitful.𝚯\nUnitful.Temperature\nUnitful.K\nUnitful.Ra\nUnitful.°C\nUnitful.°F\n```\n\n### Time\n\n```@docs\nUnitful.𝐓\nUnitful.Time\nUnitful.d\nUnitful.hr\nUnitful.minute\nUnitful.s\nUnitful.wk\nUnitful.yr\n```\n\n## Derived dimensions\n\n### Acceleration\n\n```@docs\nUnitful.Acceleration\nUnitful.Gal\nUnitful.ge\n```\n\n### Area\n\n```@docs\nUnitful.Area\nUnitful.a\nUnitful.ac\nUnitful.b\nUnitful.ha\n```\n\n### BField\n\n```@docs\nUnitful.BField\nUnitful.Gauss\nUnitful.T\n```\n\n### Capacitance\n\n```@docs\nUnitful.Capacitance\nUnitful.F\n```\n\n### Charge\n\n```@docs\nUnitful.Charge\nUnitful.C\n```\n\n### DynamicViscosity\n\n```@docs\nUnitful.DynamicViscosity\nUnitful.P\n```\n\n### ElectricalConductance\n\n```@docs\nUnitful.ElectricalConductance\nUnitful.S\n```\n\n### ElectricalResistance\n\n```@docs\nUnitful.ElectricalResistance\nUnitful.Ω\n```\n\n### Energy\n\n```@docs\nUnitful.Energy\nUnitful.btu\nUnitful.cal\nUnitful.erg\nUnitful.eV\nUnitful.J\n```\n\n### Force\n\n```@docs\nUnitful.Force\nUnitful.dyn\nUnitful.lbf\nUnitful.N\n```\n\n### Frequency\n\n```@docs\nUnitful.Frequency\nUnitful.Bq\nUnitful.Hz\nUnitful.Hz2π\nUnitful.rpm\nUnitful.rps\n```\n\n### HField\n\n```@docs\nUnitful.HField\nUnitful.Oe\n```\n\n### Inductance\n\n```@docs\nUnitful.Inductance\nUnitful.H\n```\n\n### KinematicViscosity\n\n```@docs\nUnitful.KinematicViscosity\nUnitful.St\n```\n\n### MagneticFlux\n\n```@docs\nUnitful.MagneticFlux\nUnitful.Mx\nUnitful.Wb\n```\n\n### MolarFlow\n\n```@docs\nUnitful.MolarFlow\nUnitful.kat\n```\n\n### Molarity\n\n```@docs\nUnitful.Molarity\nUnitful.M\n```\n\n### Power\n\n```@docs\nUnitful.Power\nUnitful.W\n```\n\n### Pressure\n\n```@docs\nUnitful.Pressure\nUnitful.atm\nUnitful.Ba\nUnitful.bar\nUnitful.kPa\nUnitful.Pa\nUnitful.psi\nUnitful.Torr\n```\n\n### Velocity\n\n```@docs\nUnitful.Velocity\nUnitful.c\n```\n\n### Voltage\n\n```@docs\nUnitful.Voltage\nUnitful.V\n```\n\n### Volume\n\n```@docs\nUnitful.Volume\nUnitful.L\n```\n\n## Dimensionless units\n\n```@docs\nUnitful.°\nUnitful.pcm\nUnitful.percent\nUnitful.permille\nUnitful.pertenthousand\nUnitful.ppb\nUnitful.ppm\nUnitful.ppq\nUnitful.ppt\nUnitful.rad\nUnitful.sr\n```\n\n## Logarithmic units\n\n| Unit           | Name                            |\n|----------------|---------------------------------|\n| `dB`       |        Decibel |\n| `B`        |         Bel |\n| `Np`       |        Neper |\n| `cNp`      |       Centineper |\n\n### Log units related to reference levels\n| Unit           | Reference level                            |\n|----------------|---------------------------------|\n| `dBHz`       |         1Hz |\n| `dBm`          |         1mW |\n| `dBV`          |         1V |\n| `dBu`          |         sqrt(0.6)V |\n| `dBμV`        |         1μV |\n| `dBSPL`      |         20μPa |\n| `dBFS`        |         RootPowerRatio(1) |\n| `dBΩ`          |         1Ω |\n| `dBS`          |         1S |\n\n## Physical constants\n\n```@docs\nUnitful.c0\nUnitful.G\nUnitful.gn\nUnitful.h\nUnitful.k\nUnitful.me\nUnitful.mn\nUnitful.mp\nUnitful.Na\nUnitful.q\nUnitful.R\nUnitful.R∞\nUnitful.Z0\nUnitful.ħ\nUnitful.ε0\nUnitful.μ0\nUnitful.μB\nUnitful.σ\nUnitful.Φ0\n```\n\n## Metric (SI) Prefixes\n\n| Prefix | Name | Power of Ten |\n|--------|--------|--------|\n| y | yocto | -24 |\n| z | zepto | -21 |\n| a | atto | -18 |\n| f | femto | -15 |\n| p | pico | -12 |\n| n | nano | -9 |\n| μ | micro | -6 |\n| m | milli | -3 |\n| c | centi | -2 |\n| d | deci | -1 |\n| da | deca | 1 |\n| h | hecto | 2 |\n| k | kilo | 3 |\n| M | mega | 6 |\n| G | giga | 9 |\n| T | tera | 12 |\n| P | peta | 15 |\n| E | exa | 18 |\n| Z | zetta | 21 |\n| Y | yotta | 24 |\n"
  },
  {
    "path": "docs/src/display.md",
    "content": "# How units are displayed\n\nBy default, exponents on units or dimensions are indicated using Unicode superscripts on\nmacOS and without superscripts on other operating systems. You can set the environment\nvariable `UNITFUL_FANCY_EXPONENTS` to either `true` or `false` to force using or not using\nthe exponents. You can also set the `:fancy_exponent` IO context property to either `true`\nor `false` to force using or not using the exponents.\n\n```@docs\nUnitful.BracketStyle\nUnitful.abbr\nUnitful.prefix\nUnitful.show(::IO, ::Quantity)\nUnitful.show(::IO, ::Unitful.Unitlike)\nUnitful.showrep\nUnitful.showval\nUnitful.superscript\n```\n"
  },
  {
    "path": "docs/src/extending.md",
    "content": "# Extending Unitful\n\n## Making your own units package\n\nNew units or dimensions can be defined from the Julia REPL or from within\nother packages. To avoid duplication of code and effort, it is advised to put\nnew unit definitions into a Julia package that is then published for others to\nuse. For an example of how to do this, examine the code in\n[`UnitfulUS.jl`](https://github.com/PainterQubits/UnitfulUS.jl), which defines\nU.S. customary units. It's actually very easy! Just make sure you read all of\nthe cautionary notes on this page. If you make a units package for Unitful,\nplease submit a pull request so that I can provide a link from Unitful's README!\n\n## Some limitations\n\n### Precompilation\n\nWhen creating new units in a precompiled package that need to persist into\nrun-time (usually true), it is important that the following make it into your\ncode:\n\n```julia\nfunction __init__()\n    Unitful.register(YourModule)\nend\n```\n\nBy calling [`Unitful.register`](@ref) in your `__init__` function, you tell\nUnitful about some internal data required to make Unit conversions work and\nalso make your units accessible to Unitful's [`@u_str`](@ref) macro. Your unit\nsymbols should ideally be distinctive to avoid colliding with symbols defined\nin other packages or in Unitful. If there is a collision, the [`@u_str`](@ref)\nmacro will still work, but it will use the unit found in whichever package was\nregistered most recently, and it will emit a warning every time.\n\nIf you use the `@u_str` macro with the units defined in your package, you'll\nalso need to call `Unitful.register()` at the top level of your package at\ncompile time.\n\nIn the unlikely case that you've used `@dimension`, you will also need the\nfollowing incantation:\n\n```julia\nconst localpromotion = copy(Unitful.promotion)\nfunction __init__()\n    Unitful.register(YourModule)\n    merge!(Unitful.promotion, localpromotion)\nend\n```\n\nThe definition of `localpromotion` must happen *after all new units\n(dimensions) have been defined*.\n\n### Type uniqueness\n\nCurrently, when the [`@dimension`](@ref), [`@derived_dimension`](@ref),\n[`@refunit`](@ref), or [`@unit`](@ref) macros are used, some unique symbols\nmust be provided which are used to differentiate types in dispatch. These\nare typically the names of dimensions or units (e.g. `Length`, `Meter`, etc.)\nOne problem that could occur is that if multiple units or dimensions are defined\nwith the same name, then they will be indistinguishable in dispatch and errors\nwill result.\n\nI don't expect a flood of units packages to come out, so probably the likelihood\nof name collision is pretty small. When defining units yourself, do take care to\nuse unique symbols, perhaps with the aid of `Base.gensym()` if creating units at\nruntime. When making packages, look and see what symbols are used by existing\nunits packages to avoid trouble.\n\n## Archaic or fictitious unit systems\n\nIn the rare event that you want to define physical units which are not\nconvertible to SI units, you need to do a bit of extra work. To be clear,\nsuch a conversion should always exist, in principle. One can imagine, however,\narchaic or fictitious unit systems for which a precise conversion to SI units\nis unknown. For example, a [cullishigay](https://en.wikipedia.org/wiki/Cullishigay)\nis one-third of a mudi, but only *approximately* 1.25 imperial bushels. There may\nbe cases where you don't even have an approximate conversion to imperial bushels.\nAt such a time, you may feel uncomfortable specifying the \"base unit\" of this\nhypothetical unit system in terms of an SI quantity, and may want to\nexplicitly forbid any attempt to convert to SI units.\n\nOne can achieve this by defining new dimensions with the [`@dimension`](@ref) or\n[`@derived_dimension`](@ref) macros. The trick is to define dimensions that display\nsuggestively like physical dimensions, like `𝐋*`, `𝐓*` etc., but are distinct as far\nas Julia's type system is concerned. Then, you can use [`@refunit`](@ref) to\nbase units for these new dimensions without reference to SI. The result will be\nthat attempted conversion between the hypothetical unit system and SI will fail\nwith a `DimensionError`, so be sure you provide some hints in how your\nnew dimensions are displayed to avoid confusing users. It would be confusing\nto throw a `DimensionError` when attempting to convert between lengths which are\nincompatible in the sense of the previous paragraph, when both lengths display their\ndimension as `𝐋`.\n"
  },
  {
    "path": "docs/src/highlights.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Highlighted features\n\n## Dispatch on dimensions\n\nConsider the following toy example, converting from voltage or power ratios to decibels:\n\n```jldoctest\njulia> whatsit(x::Unitful.Voltage) = \"voltage!\"\nwhatsit (generic function with 1 method)\n\njulia> whatsit(x::Unitful.Length) = \"length!\"\nwhatsit (generic function with 2 methods)\n\njulia> whatsit(1u\"mm\")\n\"length!\"\n\njulia> whatsit(1u\"kV\")\n\"voltage!\"\n\njulia> whatsit(1u\"A\" * 2.5u\"Ω\")\n\"voltage!\"\n```\n\n### Dimensions in a type definition\n\nIt may be tempting to specify the dimensions of a quantity in a type definition, e.g.\n\n```julia\nstruct Person\n    height::Unitful.Length\n    mass::Unitful.Mass\nend\n```\n\nHowever, these are abstract types. If performance is important, it may be better\njust to pick a concrete `Quantity` type:\n\n```julia\nstruct Person\n    height::typeof(1.0u\"m\")\n    mass::typeof(1.0u\"kg\")\nend\n```\n\nYou can still create a `Person` as `Person(5u\"ft\"+10u\"inch\", 75u\"kg\")`; the\nunit conversion happens automatically.\n\n## Making new units and dimensions\n\nYou can make new units using the [`@unit`](@ref) macro on the fly:\n\n```jldoctest\njulia> @unit yd5 \"yd5\" FiveYards 5u\"yd\" false\nyd5\n```\n\n## Arrays\n\nPromotion is used to create arrays of a concrete type where possible, such\nthat arrays of unitful quantities are stored efficiently in memory. However,\nif necessary, arrays can hold quantities with different dimensions, even\nmixed with unitless numbers. Doing so will suffer a performance penalty compared\nwith the fast performance attainable with an array of concrete type\n(e.g. as resulting from `[1.0u\"m\", 2.0u\"cm\", 3.0u\"km\"]`). However, it could be useful\nin toy calculations for\n[general relativity](https://en.wikipedia.org/wiki/Metric_tensor_(general_relativity))\nwhere some conventions yield matrices with mixed dimensions:\n\n```jldoctest\njulia> using LinearAlgebra\n\njulia> Diagonal([-1.0u\"c^2\", 1.0, 1.0, 1.0]);\n```\n\n## Logarithmic units\n\n```jldoctest\njulia> uconvert(u\"mW*s\", 20u\"dBm/Hz\")\n100.0 s mW\n```\n\n## Units with rational exponents\n\n```jldoctest\njulia> 1.0u\"V/sqrt(Hz)\"\n1.0 V Hz^-1/2\n```\n\n## Exact conversions respected\n\n```jldoctest\njulia> uconvert(u\"ft\",1u\"inch\")\n1//12 ft\n```\n"
  },
  {
    "path": "docs/src/index.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Unitful.jl\n\nA Julia package for physical units. Available\n[here](https://github.com/JuliaPhysics/Unitful.jl). Inspired by:\n\n- [SIUnits.jl](https://github.com/keno/SIUnits.jl)\n- [EngUnits.jl](https://github.com/dhoegh/EngUnits.jl)\n- [Units.jl](https://github.com/timholy/Units.jl)\n\nWe want to support not only SI units but also any other unit system. We also\nwant to minimize or in some cases eliminate the run-time penalty of units.\nThere should be facilities for dimensional analysis. All of this should\nintegrate easily with the usual mathematical operations and collections\nthat are defined in Julia.\n\n## Quick start\n\n- This package requires Julia 1.0. Older versions will not be supported.\n- `] add Unitful`\n- `using Unitful`\n\nUnitful aims for generality, but has some useful functionality out of the box.\n- Base dimensions like length, mass, time, etc. are defined.\n- Derived dimensions like volume, energy, momentum, etc. are defined.\n- Base and derived SI units with their power-of-ten prefixes are defined.\n- Some other common units are defined, without power-of-ten prefixes.\n- Sensible default promotion behavior is specified.\n\nTake a look at `src/pkgdefaults.jl` for a complete list. Note that some unit\nabbreviations conflict with other definitions or syntax:\n\n- `inch` is used instead of `in`, since `in` conflicts with Julia syntax\n- `minute` is used instead of `min`, since `min` is a commonly used function\n- `hr` is used instead of `h`, since `h` is revered as the Planck constant\n- `hbar` is hectobars in the SI system, so `ħ` is used for the reduced Plank\n  constant\n\n## Important note on namespaces\n\nUnits, dimensions, and fundamental constants are not exported from Unitful.\nThis is to avoid proliferating symbols in your namespace unnecessarily. You can\nretrieve them from Unitful in one of three ways:\n\n1. Use the [`@u_str`](@ref) string macro.\n2. Explicitly import from the `Unitful` package to bring specific symbols\n   into the calling namespace.\n3. `using Unitful.DefaultSymbols` will bring the following symbols into the\n   calling namespace:\n     - Dimensions `𝐋,𝐌,𝐓,𝐈,𝚯,𝐉,𝐍` for length, mass, time, current, temperature,\n       luminosity, and amount, respectively.\n     - Base and derived SI units, with SI prefixes (except for `cd`, which conflicts\n       with `Base.cd`)\n     - `°` (degrees)\n  If you have been using the [SIUnits.jl](https://github.com/keno/SIUnits.jl)\n  package, this is not unlike typing `using SIUnits.ShortUnits` with that package.\n\n## Usage examples\n\n```@meta\nDocTestSetup = quote\n    using Unitful\n    °C = Unitful.°C\n    °F = Unitful.°F\n    Ra = Unitful.Ra\n    K = Unitful.K\n    μm = Unitful.μm\n    m = Unitful.m\n    hr = Unitful.hr\n    minute = Unitful.minute\n    s = Unitful.s\n    F = Unitful.F\nend\n```\n\n```jldoctest\njulia> 1u\"kg\" == 1000u\"g\"             # Equivalence implies unit conversion\ntrue\n\njulia> !(1u\"kg\" === 1000u\"g\")         # ...and yet we can distinguish these...\ntrue\n\njulia> 1u\"kg\" === 1u\"kg\"              # ...and these are indistinguishable.\ntrue\n```\n\nIn the next examples we assume we have brought some units into our namespace,\ne.g. `const m = u\"m\"`, etc.\n\n```jldoctest\njulia> uconvert(°C, 212°F)\n100//1 °C\n\njulia> uconvert(μm/(m*Ra), 9μm/(m*K))\n5//1 μm m^-1 Ra^-1\n\njulia> mod(1hr+3minute+5s, 24s)\n17 s\n```\n\nOne useful interactive function is being able to convert to preferred (in this case SI) units. \n\n```jldoctest\njulia> upreferred(F/m)\nA^2 s^4 kg^-1 m^-3\n```\n\n!!! note\n    Quantities in `°C` or `⁠°F` always unit-convert under an affine transformation that takes\n    their relative scales into account. To avoid ambiguities that can lead to incorrect\n    results, the units `°C` and `°F` cannot be used in Unitful to represent temperature\n    differences. Fortunately, `1°C - 0°C == 1K` and `1°F - 0°F == 1Ra`, so the absolute\n    temperature scales Kelvin (`K`) and Rankine (`Ra`) can be used easily to represent\n    temperature differences.\n\nSee `test/runtests.jl` for more usage examples.\n\n## About the logo\n\nThe logo is a pictorial representation of the [International Prototype of the Kilogram](https://en.wikipedia.org/wiki/International_Prototype_of_the_Kilogram), which was the standard definition of one kilogram from 1889 to 2019,\nwhen it was replaced by a definition based on the Planck constant, the speed of light, and the ground-state hyperfine transition frequency of ¹³³Cs.\n"
  },
  {
    "path": "docs/src/latexify.md",
    "content": "# Latexify extension\n\nUnitful has an extension for [Latexify](https://github.com/korsbo/Latexify.jl), which was formerly implemented as a separate package called UnitfulLatexify.jl.\n\nThe default usage is pretty intuitive:\n\n```@setup main\nusing LaTeXStrings # for some manual pretty-printing\n```\n\n```@example main\nusing Unitful, Latexify\n\na = 9.82u\"m/s^2\"\nt = 4u\"s\"\nx = a*t^2\n\nlatexify(x)\n```\n\nor more usefully:\n\n```@example main\nlatexify(:(x = a*t^2 = $x))\n```\n\nThis of course also works for `Units` objects by themselves:\n\n```@example main\nlatexify(u\"kg*m\")\n```\n\nSome more usage examples:\n\n![](assets/latex-examples.png)\n\n\n## Arrays\n\nBecause Latexify is recursive, an array of unitful quantities is shown as\nexpected:\n\n\n```@example main\nlatexify([12u\"m\", 1u\"m^2\", 4u\"m^3\"])\nLaTeXString(\"\\$\" * chopsuffix(chopprefix(ans, \"\\\\begin{equation}\\n\"), \"\\n\\\\end{equation}\\n\") * \"\\$\") # hide\n```\n\nA special case is an array where all elements have the same unit, and here\nthe extension does some extra work:\n```@example main\nlatexify([1, 2, 3]u\"cm\")\nLaTeXString(\"\\$\" * chopsuffix(chopprefix(ans, \"\\\\begin{equation}\\n\"), \"\\n\\\\end{equation}\\n\") * \"\\$\") # hide\n```\n\n\n## siunitx.sty\n\nIf you are exporting your numbers to an actual LaTeX document, you will of\ncourse want to use the commands from `siunitx.sty` rather than the `\\mathrm`\nstyle used by default. To this end you can use Latexify's `fmt=SiunitxNumberFormatter` for `\\qty{8}{\\second\\meter\\per\\kilo\\gram}` style and `fmt=SiunitxNumberFormatter(simple=true)` for\n`\\qty{8}{s.m/kg}`. Like other Latexify keywords, this can be set to be a default\nby using `set_default(fmt=SiunitxNumberFormatter())`, or given with each latexification\ncommand:\n\n```@example main\nlatexify(612.2u\"nm\"; fmt=SiunitxNumberFormatter()) # This will not render right without the `siunitx` package\nprint(ans) # hide\n```\n\n### Lists\n\nAnother thing that `siunitx` does uniquely is lists and ranges of quantities.\nTo get `siunitx`'s list behavior, pass a tuple instead of an array;\nif you want a tuple to be written as an array instead, use `collect(x)` or `[x...]` to convert it into an array first.\n\n```@example main\nlatexify((1, 2, 3).*u\"m\")\nprint(ans) # hide\n```\n```@example main\nlatexify((1, 2, 3).*u\"m\"; fmt=SiunitxNumberFormatter())\nprint(ans) # hide\n```\n```@example main\nlatexify(collect((1, 2, 3).*u\"m\"); fmt=SiunitxNumberFormatter())\nprint(ans) # hide\n```\n\n\n## Plots labels\n\nThis extension also interfaces with `Plots` by way of implementing a two-argument `(label, unit)` recipe:\n\n```@example main\nlatexify(\"v\", u\"km/s\")\n```\n\nThis enables this dreamlike example:\n\n```@example plot\nusing Unitful, Plots, Latexify \ngr()\ndefault(fontfamily=\"Computer Modern\")\n\nm = randn(10)u\"kg\"\nv = randn(10)u\"m/s\"\nplot(m, v; xguide=\"\\\\mathrm{mass}\", yguide=\"v_x\", unitformat=latexify)\n```\n\nThis format, ``v_x\\;\\left/\\;\\mathrm{m}\\,\\mathrm{s}^{-1}\\right.``, is subject to personal\npreference. A couple other defaults are provided:\n- `:slash`, ``v_x\\;\\left/\\;\\mathrm{m}\\,\\mathrm{s}^{-1}\\right.``\n- `:round`, ``v_x\\;\\left(\\mathrm{m}\\,\\mathrm{s}^{-1}\\right)``\n- `:square`, ``v_x\\;\\left[\\mathrm{m}\\,\\mathrm{s}^{-1}\\right]``\n- `:frac`, ``\\frac{v_x}{\\mathrm{m}\\,\\mathrm{s}^{-1}}``\n\nTo use these in a plot call, either pass a function like \n```\n(l,u) -> latexify(l, u; labelformat=:slash)` \n```\nor call `Latexify.set_default(labelformat=:square)`, then pass `latexify` as your unitformat.\n\n```@example plot\nargs = (m, v)\nkwargs = (xguide=\"\\\\mathrm{mass}\", yguide=\"v_x\", legend=false)\nLatexify.set_default(labelformat=:square)\nplot(\n\tplot(args...; kwargs..., unitformat=(l,u)->latexify(l, u, labelformat=:slash)),\n\tplot(args...; kwargs..., unitformat=(l, u)->latexify(l, u, labelformat=:round)),\n\tplot(args...; kwargs..., unitformat=latexify),\n\tplot(args...; kwargs..., unitformat=(l, u)->latexify(l, u, labelformat=:frac)),\n\tplot(args...; kwargs..., unitformat=(l, u)->string(\"\\$\", l, \" \\\\rightarrow \", latexraw(u), \"\\$\")),\n)\n```\n\n## Pluto notebooks\nOne use case is in Pluto notebooks, where you can\nwrite\n\n```julia\nMarkdown.parse(\"\"\"\nThe period is $(@latexrun T = $(2.5u\"ms\")), so the frequency is $(@latexdefine f = 1/T post=u\"kHz\").\n\"\"\")\n```\nwhich renders as\n\n> The period is $T = 2.5\\;\\mathrm{ms}$, so the frequency is $f = \\frac{1}{T} = 0.4\\;\\mathrm{kHz}$.\n\nNote that the quantity has to be interpolated (put inside a\ndollar-parenthesis), or Latexify will interpret it as a multiplication between\na number and a call to `@u_str`.\n\n\n## Per-modes\n\nIn mathrm-mode, one might prefer ``\\mathrm{J}\\,/\\,\\mathrm{kg}`` or\n``\\frac{\\mathrm{J}}{\\mathrm{kg}}`` over ``\\mathrm{J}\\,\\mathrm{kg}^{-1}``. This\ncan be achieved by supplying `permode=:slash` or `permode=:frac` respectively, rather than the default `permode=:power`.\n\nThese will have no effect with `SiunitxNumberFormatter`, because the latex package handles\nthis for you, and you can set it in your document.\n\n## New siunitx syntax\n\nThe new syntax from `siunitx v3` (`\\qty, \\unit` rather\nthan `\\SI, \\si`) is used by default. If you cannot upgrade `siunitx`, there's the option\nto use `fmt=SiunitxNumberFormatter(version=2)`.\n\n## A more complete list of defined units\n\nBelow is a poorly scraped list of units defined in `Unitful` and what comes out\nif you run it through `latexify`. Feel free to create an issue if there's a\nunit missing or being incorrectly rendered (and suggest a better ``\\LaTeX``\nrepresentation if you know one).\n\n![](assets/latex-allunits.png)\n"
  },
  {
    "path": "docs/src/logarithm.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Logarithmic scales\n\n!!! note \n\n    Logarithmic scales should be considered experimental \n    because they break some of the basic assumptions about equality and hashing \n    (see [#402](https://github.com/JuliaPhysics/Unitful.jl/issues/402))\n\nUnitful provides a way to use logarithmically-scaled quantities. Some\ncompromises have been made in striving for logarithmic quantities to be both usable and\nconsistent. In the following discussion, for pedagogical purposes, we will assume prior\nfamiliarity with the definitions of `dB` and `dBm`.\n\n## Constructing logarithmic quantities\n\nLeft- or right-multiplying a pure number by a logarithmic \"unit\", whether dimensionful or\ndimensionless, is short-hand for constructing a logarithmic quantity.\n\n```jldoctest\njulia> 3u\"dB\"\n3 dB\n\njulia> 3u\"dBm\"\n3.0 dBm\n\njulia> u\"dB\"*3 === 3u\"dB\"\ntrue\n```\n\nCurrently implemented are `dB`, `B`, `dBm`, `dBV`, `dBu`, `dBμV`, `dBSPL`, `dBFS`, `cNp`,\n`Np`.\n\nOne can also construct logarithmic quantities using the `@dB`, `@B`, `@cNp`, `@Np` macros to\nuse an arbitrary reference level:\n\n```jldoctest\njulia> using Unitful: mW, V\n\njulia> @dB 10mW/mW\n10.0 dBm\n\njulia> @dB 10V/V\n20.0 dBV\n\njulia> @dB 3V/4V\n-2.498774732165999 dB (4 V)\n\njulia> @Np ℯ*V/V    # ℯ = 2.71828...\n1.0 Np (1 V)\n```\n\nThese macros are exported by default since empirically macros are defined less often than\nvariables and generic functions. When using the macros, the levels are constructed at parse\ntime. The scales themselves are callable as functions if you need to construct a level that\nway (they are not exported):\n\n```jldoctest\njulia> using Unitful: dB, mW, V\n\njulia> dB(10mW,mW)\n10.0 dBm\n```\n\nIn calculating the logarithms, the log function appropriate to the scale in question is used\n(`log10` for decibels, `log` for nepers).\n\nThere is an important difference in these two approaches to constructing logarithmic\nquantities. When we construct `0dBm`, the power in `mW` is calculated and stored,\nresulting in a lossy floating-point conversion. This can be avoided by constructing\n`0 dBm` as `@dB 1mW/mW`.\n\nIt is important to keep in mind that the reference level is just used to calculate the\nlogarithms, and nothing more. When there is ambiguity about what to do, we fall back\nto the underlying linear quantities, paying no mind to the reference levels:\n\n```jldoctest\njulia> using Unitful: mW\n\njulia> (@dB 10mW/1mW) + (@dB 10mW/2mW)\n20 mW\n```\n\nAddition will be discussed more later.\n\nNote that logarithmic \"units\" can only multiply or be multiplied by pure numbers and linear\nunits, not other logarithmic units or quantities. This is done to avoid issues with\ncommutativity and associativity, e.g. `3*dB*m^-1 == (3dB)/m`, but `3*m^-1*dB == (3m^-1)*dB`\ndoes not make much sense. This is because `dB` acts more like a constructor than a proper\nunit.\n\nThe `@dB` and `@Np` macros will fail if either a dimensionless number or a ratio of\ndimensionless numbers is used. This is because the ratio could be of power quantities or of\nroot-power quantities, leading to ambiguities. After all, usually it is the ratio that is\ndimensionless, not the numerator and denominator that make up the ratio. In some cases\nit may nonetheless be convenient to have a dimensionless reference level. By providing an\nextra `Bool` argument to these macros, you can explicitly choose whether the resulting ratio\nshould be considered a \"root-power\" or \"power\" ratio. You can only do this for dimensionless\nnumbers:\n\n```jldoctest\njulia> @dB 10/1 true   # is a root-power (amplitude) ratio\n20.0 dBFS\n\njulia> @dB 10/1 false  # is not a root-power ratio; is a power ratio\n10.0 dB (power ratio with reference 1)\n```\n\nNote that `dBFS` is defined to represent amplitudes relative to 1 in `dB`, hence the\ncustom display logic.\n\nAlso, you can of course use functions instead of macros:\n\n```jldoctest\njulia> using Unitful: dB, mW\n\njulia> dB(10,1,true)\n20.0 dBFS\n\njulia> dB(10mW,mW,true)\nERROR: ArgumentError: when passing a final Bool argument, this can only be used with dimensionless numbers.\n[...]\n```\n\n### Logarithmic quantities with no reference level specified\n\nLogarithmic quantities with no reference level specified typically represent some amount of\ngain or attenuation, i.e. a ratio which is dimensionless. These can be constructed as,\nfor example, `10*dB`, which displays similarly (`10 dB`). The type of this kind of\nlogarithmic quantity is:\n\n```@docs\n    Unitful.Gain\n```\n\nOne might expect that any gain / attenuation factor should be convertible to a pure number,\nthat is, to `x == y/z` if you had `10*log10(x)` dB. However, it turns out that in dB, a ratio\nof powers is defined as `10*log10(y/z)`, but a ratio of voltages or other root-power\nquantities is defined as `20*log10(y/z)`. Clearly, converting back from decibels to a real\nnumber is ambiguous, and so we have not implemented automatic promotion to avoid incorrect\nresults. You can use [`Unitful.uconvertp`](@ref) to interpret a `Gain` as a ratio of power\nquantities (hence the `p` in `uconvertp`), or [`Unitful.uconvertrp`](@ref) to interpret as\na ratio of root-power (field) quantities.\n\n### \"Dimensionful\" logarithmic quantities?\n\nIn this package, quantities with units like `dBm` are considered to have the dimension of\npower, even though the expression `P(dBm) = 10*log10(P/1mW)` is dimensionless and formed\nfrom a dimensionless ratio. Practically speaking, these kinds of logarithmic quantities are\nfungible whenever they share the same dimensions, so it is more convenient to adopt this\nconvention (people refer to `dBm/Hz` as a power spectral density, etc.) Presumably, one\nwould like to have `10dBm isa Unitful.Power` for dispatch too. Therefore, in the following\ndiscussion, we will shamelessly (okay, with some shame) speak of dimensionful logarithmic\nquantities, or `Level`s for short:\n\n```@docs\n    Unitful.Level\n```\n\nActually, the defining characteristic of a `Level` is that it has a reference level,\nwhich may or may not be dimensionful. It usually is, but is not in the case of e.g. `dBFS`.\n\nFinally, for completeness we note that both `Level` and `Gain` are subtypes of `LogScaled`:\n\n```@docs\n    Unitful.LogScaled\n```\n\n## Multiplication rules\n\nMultiplying a dimensionless logarithmic quantity by a pure number acts as like it does for\nlinear quantities:\n\n```jldoctest\njulia> 3u\"dB\" * 2\n6 dB\n\njulia> 2 * 0u\"dB\"\n0 dB\n```\n\nJustification by example: consider the example of the exponential attenuation of a signal on\na lossy transmission line. If the attenuation goes like $10^{-kx}$, then the (power)\nattenuation in dB is $-10kx$. We see that the attenuation in dB is linear in length. For an\nattenuation constant of 3dB/m, we better calculate 6dB for a length of 2m.\n\nMultiplying a dimensionful logarithmic quantity by a pure number acts differently than\nmultiplying a gain/attenuation by a pure number. Since `0dBm == 1mW`, we better have that\n`0dBm * 2 == 2mW`, implying:\n\n```jldoctest\njulia> 0u\"dBm\" * 2\n3.010299956639812 dBm\n```\n\nLogarithmic quantities can only be multiplied by pure numbers, linear units, or quantities,\nbut not logarithmic \"units\" or quantities.  When a logarithmic quantity is multiplied by a\nlinear quantity, the logarithmic quantity is linearized and multiplication proceeds as\nusual:\n\n```jldoctest\njulia> (0u\"dBm\") * (1u\"W\")\n1.0 mW W\n```\n\nThe previous example returns a floating point value because in constructing the level\n`0 dBm`, the power in `mW` is calculated and stored, entailing a floating point\nconversion. This can be avoided by constructing `0 dBm` as `@dB 1mW/mW`:\n\n```jldoctest\njulia> (@dB 1u\"mW\"/u\"mW\") * (1u\"W\")\n1 mW W\n```\n\nWe refer to a quantity with both logarithmic \"units\" and linear units as a mixed quantity.\nFor mixed quantities, the numeric value associates with the logarithmic unit, and the\nquantity is displayed in a way that makes this explicit:\n\n```jldoctest\njulia> (0u\"dBm\")/u\"Hz\"\n[0.0 dBm] Hz^-1\n\njulia> (0u\"dB\")/u\"Hz\"\n[0 dB] Hz^-1\n\njulia> 0u\"dB/Hz\"\n[0 dB] Hz^-1\n```\n\nMathematical operations are forwarded to the logarithmic part, so that for example,\n`100*((0dBm)/s) == (20dBm)/s`. We allow linear units to commute with logarithmic quantities\nfor convenience, though the association is understood (e.g. `s^-1*(3dBm) == (3dBm)/s`).\n\nThe behavior of multiplication is summarized in the following table, with entries marked by\n† indicating prohibited operations.\n\n```@eval\nusing Latexify, Unitful\nhead = [\"10\", \"Hz^-1\", \"dB\", \"dBm\", \"1/Hz\", \"1mW\", \"3dB\", \"3dBm\"]\nside = [\"*\"; \"**\" .* head .* \"**\"]\nquantities = uparse.(head)\ntab = fill(\"\", length(head), length(head))\nfor col = eachindex(head), row = 1:col\n    try\n        tab[row, col] = sprint(show, quantities[row] * quantities[col], context = :compact => true)\n    catch\n        if quantities[row] === u\"1/Hz\" && quantities[col] === u\"3dB\"\n            tab[row, col] = \"† ‡\"\n        else\n            tab[row, col] = \"†\"\n        end\n    end\nend\nmdtable(tab, latex=false, head=head, side=side)\n```\n\n‡: `1/Hz * 3dB` could be allowed, technically, but we throw an error if it's unclear whether\na quantity is a root-power or power quantity:\n\n```jldoctest\njulia> u\"1/Hz\" * u\"3dB\"\nERROR: undefined behavior. Please file an issue with the code needed to reproduce.\n```\n\nOn the other hand, if it can be determined that a power quantity or root-power quantity\nis being multiplied by a gain, then the gain is interpreted as a power ratio or root-power\nratio, respectively:\n\n```jldoctest\njulia> 1u\"mW\" * 20u\"dB\"\n100.0 mW\n\njulia> 1u\"V\" * 20u\"dB\"\n10.0 V\n```\n\n## Addition rules\n\nWe can add logarithmic quantities without reference levels specified (`Gain`s):\n\n```jldoctest\njulia> 20u\"dB\" + 20u\"dB\"\n40 dB\n```\n\nThe numbers out front of the `dB` just add: when we talk about gain or attenuation,\nwe work in logarithmic units so that we can add rather than multiply gain factors. The same\nbehavior holds when we add a `Gain` to a `Level` or vice versa:\n\n```jldoctest\njulia> 20u\"dBm\" + 20u\"dB\"\n40.0 dBm\n```\n\nIn the case where you have differing logarithmic scales for the `Level` and the `Gain`,\nthe logarithmic scale of the `Level` is used for the result:\n\n```jldoctest\njulia> 10u\"dBm\" - 1u\"Np\"\n1.3141103619349632 dBm\n```\n\nFor logarithmic quantities with the same reference levels, the numbers out in front do not\nsimply add:\n\n```jldoctest\njulia> 20u\"dBm\" + 20u\"dBm\"\n23.010299956639813 dBm\n\njulia> 2 * 20u\"dBm\"\n23.010299956639813 dBm\n```\n\nThis is because `dBm` represents a power, ultimately. If we have some amount of power and\nwe double it, we'd better get roughly `3 dB` more power. Note that the juxtaposition `20dBm`\nwill ensure that 20 dBm is constructed before multiplication by 2 in the above example.\nIf you were to type `2*20*dBm`, you'd get 40 dBm.\n\nIf the reference levels differ but both levels represent a power, we fall back to linear\nquantities:\n\n```jldoctest\njulia> 20u\"dBm\" + @dB 1u\"W\"/u\"W\"\n1.1 kg m^2 s^-3\n```\ni.e. `1.1 W`.\n\nRules for addition are summarized in the following table, with entries marked by †\nindicating prohibited operations.\n\n```@eval\nusing Latexify, Unitful\nhead = [\"100\", \"20dB\", \"1Np\", \"10.0dBm\", \"10.0dBV\", \"1mW\"]\nside = [\"+\"; \"**\" .* head .* \"**\"]\nquantities = uparse.(head)\ntab = fill(\"\", length(head), length(head))\nfor col = eachindex(head), row = 1:col\n    try\n        tab[row, col] = sprint(show, quantities[row] + quantities[col], context = :compact => true)\n    catch\n        tab[row, col] = \"†\"\n    end\nend\nmdtable(tab, latex=false, head=head, side=side)\n```\n\nNotice that we disallow implicit conversions between dimensionless logarithmic quantities\nand real numbers. This is because the results can depend on promotion rules in addition to\nbeing ambiguous because of the root-power vs. power ratio issue. If `100 + 10dB` were\nevaluated as `20dB + 10dB == 30dB`, then we'd get `1000`, but if it were evaluated as\n`100+10`, we'd get `110`.\n\nAlso, although it is possible in principle to add e.g. `20dB + 1Np`, notice that we have\nnot implemented that because it is unclear whether the result should be in nepers or\ndecibels, and it is also unclear how to handle that question more generally as other\nlogarithmic scales are introduced.\n\n## Conversion\n\nAs alluded to earlier, conversions can be tricky because so-called logarithmic units are not\nunits in the conventional sense.\n\nYou may use [`linear`](@ref) to convert to a linear scale when you have a `Level` or\n`Quantity{<:Level}` type. There is a fallback for `Number`, which just returns the number.\n\n```jldoctest\njulia> linear(@dB 10u\"mW\"/u\"mW\")\n10 mW\n\njulia> linear(20u\"dBm/Hz\")\n100.0 mW Hz^-1\n\njulia> linear(30u\"W\")\n30 W\n\njulia> linear(12)\n12\n```\n\nLinearizing a `Quantity{<:Gain}` or a `Gain` to a real number is ambiguous, because the real\nnumber may represent a ratio of powers or a ratio of root-power (field) quantities. We\nimplement [`Unitful.uconvertp`](@ref) and [`Unitful.uconvertrp`](@ref) which may be\nthought of as disambiguated `uconvert` functions. There is a one argument version that\nassumes you are converting to a unitless number. These functions can take either a `Gain`\nor a `Real` so that they may be used somewhat generically.\n\n```jldoctest\njulia> uconvertrp(NoUnits, 20u\"dB\")\n10.0\n\njulia> uconvertp(NoUnits, 20u\"dB\")  \n100.0\n\njulia> uconvertp(u\"dB\", 100)\n20.0 dB\n\njulia> uconvertp(u\"Np\", ℯ^2)\n1.0 Np\n\njulia> uconvertrp(u\"Np\", ℯ)\n1//1 Np\n```\n\n## Notation\n\nThis package displays logarithmic quantities using shorthand like `dBm` where available.\nThis should probably not be done in polite company. To quote \"Guide for the Use of the\nInternational System of Units (SI),\" NIST Special Pub. 811 (2008):\n\n> The rules of Ref. [5: IEC 60027-3] preclude, for example, the use of the symbol dBm to\n> indicate a reference level of power of 1 mW. This restriction is based on the rule of Sec.\n> 7.4, which does not permit attachments to unit symbols.\n\nThe authorities say the reference level should always specified. In practice, this hasn't\nstopped the use of `dBm` and the like on commercially available test equipment. Dealing with\nthese units is unavoidable in practice. When no shorthand exists, we follow NIST's advice in\ndisplaying logarithmic quantities:\n\n> When such data are presented in a table or in a figure, the following condensed notation\n> may be used instead: -0.58 Np (1 μV/m); 25 dB (20 μPa).\n\n## Custom logarithmic scales\n\n```@docs\n    Unitful.@logscale\n```\n\n## API\n\n```@docs\n    Unitful.linear\n    Unitful.logunit\n    Unitful.reflevel\n    Unitful.uconvertp\n    Unitful.uconvertrp\n```\n"
  },
  {
    "path": "docs/src/manipulations.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\n    using InverseFunctions\nend\n```\n# Manipulating units\n\n## Unitful string macro\n\n```@docs\nUnitful.@u_str\nUnitful.register\n```\n\n## Dimension and unit inspection\n\nWe define a function [`dimension`](@ref) that turns, for example, `acre^2` or `1*acre^2`\ninto `𝐋^4`. We can usually add quantities with the same dimension, regardless of specific\nunits (`FixedUnits` cannot be automatically converted, however). Note that dimensions cannot\nbe determined by powers of the units: `ft^2` is an area, but so is `ac^1` (an acre).\n\nThere is also a function [`unit`](@ref) that turns, for example, `1*acre^2` into `acre^2`.\nYou can then query whether the units are `FreeUnits`, `FixedUnits`, etc.\n\n```@docs\nUnitful.unit\nUnitful.dimension\n```\n\n## Unit stripping\n\n```@docs\nUnitful.ustrip\n```\n\n## Unit multiplication\n\n```@docs\n*(::Unitful.Units, ::Unitful.Units...)\n*(::Unitful.Dimensions, ::Unitful.Dimensions...)\n```\n"
  },
  {
    "path": "docs/src/newunits.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Defining new units\n\n!!! note\n    Logarithmic units should not be used in the `@refunit` or `@unit` macros described below.\n    See the section on logarithmic scales for customization help.\n\nThe package automatically generates a useful set of units and dimensions in the\n`Unitful` module in `src/pkgdefaults.jl`.\n\nIf a different set of default units or dimensions is desired, macros for\ngenerating units and dimensions are provided. To create new units\ninteractively, most users will be happy with the [`@unit`](@ref) macro\nand the [`Unitful.register`](@ref) function, which makes units defined in a module\navailable to the [`@u_str`](@ref) string macro.\n\nAn example of defining units in a module:\n\n```jldoctest\njulia> module MyUnits; using Unitful; @unit myMeter \"m\" MyMeter 1u\"m\" false; end\nMyUnits\n\njulia> using Unitful\n\njulia> u\"myMeter\"\nERROR: LoadError:\n[...]\n\njulia> Unitful.register(MyUnits);\n\njulia> u\"myMeter\"\nm\n```\n\nYou could have also called `Unitful.register` inside the `MyUnits` module; the choice is\nsomewhat analogous to whether or not to export symbols from a module, although the symbols\nare never really exported, just made available to the `@u_str` macro. If you want to make a\nprecompiled units package, rather than define a module at the REPL,\nsee [Making your own units package](@ref).\n\nYou can also define units directly in the `Main` module at the REPL:\n\n```jldoctest\njulia> using Unitful\n\njulia> Unitful.register(@__MODULE__);\n\njulia> @unit M \"M\" Molar 1u\"mol/L\" true;\n\njulia> 1u\"mM\"\n1 mM\n```\n\nA note for the experts: Some care should be taken if explicitly creating\n[`Unitful.Units`](@ref) objects. The ordering of [`Unitful.Unit`](@ref) objects\ninside a tuple matters for type comparisons. Using the unary multiplication\noperator on the `Units` object will return a \"canonically sorted\" `Units` object.\nIndeed, this is how we avoid ordering issues when multiplying quantities together.\n\n## Defining units in precompiled packages\n\nSee [Precompilation](@ref).\n\n## Useful functions and macros\n```@docs\nUnitful.@dimension\nUnitful.@derived_dimension\nUnitful.@refunit\nUnitful.@unit\nUnitful.@affineunit\n```\n\n## Internals\n```@docs\nUnitful.@prefixed_unit_symbols\nUnitful.@unit_symbols\nUnitful.basefactor\n```\n"
  },
  {
    "path": "docs/src/temperature.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\n    using Unitful:AffineError\nend\n```\n# Temperature scales\n\nTemperatures require some care. Temperature scales like `K` and `Ra` are thermodynamic\ntemperature scales, with zero on the scale corresponding to absolute zero. Unit conversions\nbetween thermodynamic or absolute temperatures are done by multiplying conversion factors,\nas usual. Also in common use are temperature scales like `°C` or `°F`, which are defined\nrelative to arbitrary offsets. For example, in the case of `°C`, zero on the scale is the\nfreezing point of water, not absolute zero. To convert between relative temperature scales,\nan affine transformation is required. Absolute and relative temperatures can be\ndistinguished by type to avoid ambiguities that could yield erroneous or unexpected results.\nOn relative temperature scales, problems can arise because e.g. `0°C + 0°C` could mean `0°C`\nor `273.15°C`, depending on whether the operands are variously interpreted as temperature\ndifferences or as absolute temperatures. On thermodynamic temperature scales, there is no\nambiguity.\n\n## Temperatures on absolute scales\n\nUnit conversions between temperatures on absolute scales like Kelvin or Rankine are done in\nthe usual way by multiplication of a scale factor. For example, we have:\n\n```jldoctest\njulia> uconvert(u\"K\", 1u\"Ra\")\n5//9 K\n```\n\nWe can identify absolute temperatures using the `Unitful.AbsoluteScaleTemperature` type\nalias:\n\n```jldoctest\njulia> 1u\"K\" isa Unitful.AbsoluteScaleTemperature\ntrue\n```\n\n## Temperatures on relative scales\n\nUnit conversions between temperatures on relative scales like Celsius or Fahrenheit involve\nan affine transformation, that is, a scaling plus some translation (scale offset). In\nUnitful, relative scale temperatures are considered to have the same dimension as absolute\nscale temperatures, as expected. However, temperatures on relative and absolute scales are\ndistinguished by the type of the [`Unitful.Units`](@ref) object (and therefore the type of\nthe [`Unitful.Quantity`](@ref) object).\n\n```jldoctest\njulia> uconvert(u\"°C\", 32u\"°F\")\n0//1 °C\n```\n\nWe can identify relative scale temperatures using the `Unitful.RelativeScaleTemperature`\ntype alias, e.g.:\n\n```jldoctest\njulia> 1u\"°C\" isa Unitful.RelativeScaleTemperature\ntrue\n```\n\nSome operations are not well defined with relative scale temperatures, and therefore throw\nan `Unitful.AffineError` (please report any unexpected behavior on the GitHub issue\ntracker).\n\n```jldoctest\njulia> 32u\"°F\" + 1u\"°F\"\nERROR: AffineError: an invalid operation was attempted with affine quantities: 32 °F + 1 °F\n[...]\n\njulia> 32u\"°F\" * 2\nERROR: AffineError: an invalid operation was attempted with affine quantities: 32 °F*2\n[...]\n```\n\nThere is a general mechanism for making units that indicate quantities should unit-convert\nunder some affine transformation. While the usual use case is for relative scale\ntemperatures, nothing in the implementation limits it as such. Accordingly, relative scale\ntemperatures are considered to be [`Unitful.AffineQuantity`](@ref) objects with dimensions\nof temperature. The units on \"affine quantities\" are [`Unitful.AffineUnits`](@ref) objects.\n\nMaking your own affine units typically requires two steps. First, define the absolute unit\nusing the [`Unitful.@unit`](@ref) macro. Second, use the [`Unitful.@affineunit`](@ref) macro\nto make a corresponding affine unit. As an example, this is how `Ra` and `°F` are\nimplemented:\n\n```julia\n@unit Ra \"Ra\" Rankine (5//9)*K false\n@affineunit °F \"°F\" (45967//100)Ra\n```\n\nThe preferred unit for promoting temperatures is usually `K` when using\n[`Unitful.FreeUnits`](@ref).\n\n```@docs\nUnitful.AffineUnits\nUnitful.AffineQuantity\nUnitful.ScalarUnits\nUnitful.ScalarQuantity\nUnitful.absoluteunit\n```\n"
  },
  {
    "path": "docs/src/trouble.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Troubleshooting\n\n## Why do unit conversions yield rational numbers sometimes?\n\nWe use rational numbers in this package to permit exact conversions\nbetween different units where possible. As an example, one inch is exactly equal\nto 2.54 cm. However, in Julia, the floating-point `2.54` is not equal to\n`254//100`. As a consequence, `1inch != 2.54cm`, because Unitful respects exact\nconversions. To test for equivalence, instead use `≈` (`\\approx`\ntab-completion).\n\n### But I want a floating point number...\n\n`float(x)` is defined for [`Unitful.Quantity`](@ref) types,\nand is forwarded to the underlying numeric type (units are not affected).\n\nWe may consider adding an option in the defaults to turn on/off use of `Rational`\nnumbers. They permit exact conversions, but they aren't preferred as a result\ntype in much of Julia Base (consider that `inv(2) === 0.5`, not `1//2`).\n\n## Exponentiation\n\nMost operations with this package should in principle suffer little performance\npenalty if any at run time. An exception to this is rule is exponentiation.\nSince units and their powers are encoded in the type signature of a\n[`Unitful.Quantity`](@ref) object, raising a `Quantity` to some power, which is\njust some run-time value, necessarily results in different result types.\nThis type instability could impact performance:\n\n```jldoctest\njulia> square(x) = (p = 2; x^p)\nsquare (generic function with 1 method)\n```\n\nIn Julia, constant literal integers are lowered specially for exponentiation.\n(See Julia PR [#20530](https://github.com/JuliaLang/julia/pull/20530) for details.)\nIn this case, type stability can be maintained:\n\n```jldoctest\njulia> square(x) = x^2\nsquare (generic function with 1 method)\n```\n\nBecause the functions `inv`, `sqrt`, and `cbrt` are raising a `Quantity` to a fixed\npower (-1, 1/2, and 1/3, respectively), we can use a generated function to ensure\ntype stability in these cases. Also note that squaring a `Quantity` can be\ntype-stable if done as `x*x`.\n\n## Promotion with dimensionless numbers\n\nMost of the time, you are only permitted to do sensible operations in Unitful.\nWith dimensionless numbers, some of the safe logic breaks down. Consider for\ninstance that `μm/m` and `rad` are both dimensionless units, but kind of have\nnothing to do with each other. It would be a little weird to add them. Nonetheless,\nwe permit this to happen since they have the same dimensions. Otherwise, we\nwould have to special-case operations for two dimensionless quantities rather\nthan dispatching on the empty dimension.\n\nThe result of addition and subtraction with dimensionless but unitful numbers\nis always a pure number with no units. With angles, `1 rad` is essentially just\n`1`, giving sane behavior:\n\n```jldoctest\njulia> π/2*u\"rad\"+90u\"°\"\n3.141592653589793\n```\n\n## Broken display of dimension characters in the REPL\n\nOn some terminals with some fonts, dimension characters such as `𝐌` are displayed as an\nempty box. Setting a wider font spacing in your terminal settings can solve this problem.\n\n## I have a different problem\n\nPlease raise an issue. This package is in development and there may be bugs.\nFeature requests may also be considered and pull requests are welcome.\n"
  },
  {
    "path": "docs/src/types.md",
    "content": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Types\n\n## Overview\nWe define a [`Unitful.Unit{U,D}`](@ref) type to represent a unit (`U` is a symbol,\nlike `:Meter`, and `D` keeps track of dimensional information).\nFields of a `Unit` object keep track of a rational exponents and a power-of-ten\nprefix. We don't allow arbitrary floating point exponents of units because they\nprobably aren't very useful. The prefixes on units (e.g. `nm` or `km`) may help\nto avoid overflow issues and general ugliness.\n\nUsually, the user interacts only with `Units` objects, not `Unit` objects.\nThis is because generically, more than one unit is needed to describe a quantity.\nAn abstract type [`Unitful.Units{N,D,A}`](@ref) is defined, where `N` is always a tuple\nof `Unit` objects, `D` is a [`Unitful.Dimensions{N}`](@ref) object such as `𝐋`, the\nobject representing the length dimension, and `A` is a translation for affine quantities.\n\nSubtypes of `Unitful.Units{N,D,A}` are used to implement different behaviors\nfor how to promote dimensioned quantities. The concrete subtypes have no fields and\nare therefore immutable singletons. Currently implemented subtypes of `Unitful.Units{N,D,A}`\ninclude [`Unitful.FreeUnits{N,D,A}`](@ref), [`Unitful.ContextUnits{N,D,P,A}`](@ref), and\n[`Unitful.FixedUnits{N,D,A}`](@ref). Units defined in the Unitful.jl package itself are all\n`Unitful.FreeUnits{N,D,A}` objects.\n\nFinally, we define physical quantity types as [`Quantity{T<:Number, D, U}`](@ref), where\n`D :: Dimensions` and `U <: Units`. By putting units in the type signature of a\nquantity, staged functions can be used to offload as much of the unit\ncomputation to compile-time as is possible. By also having the dimensions\nexplicitly in the type signature, dispatch can be done on dimensions:\n`isa(1u\"m\", Unitful.Length) == true`. This works because `Length` is a type alias for\nsome subset of `Unitful.Quantity` subtypes.\n\n## API\n\n### Quantities\n\n```@docs\n    Unitful.AbstractQuantity\n    Unitful.Quantity\n    Unitful.DimensionlessQuantity\n```\n\n### Units and dimensions\n\n```@docs\n    Unitful.Unitlike\n    Unitful.Units\n    Unitful.FreeUnits\n    Unitful.ContextUnits\n    Unitful.FixedUnits\n    Unitful.Dimensions\n    Unitful.Unit\n    Unitful.Dimension\n\tUnitful.NoDims\n```\n"
  },
  {
    "path": "ext/ConstructionBaseUnitfulExt.jl",
    "content": "module ConstructionBaseUnitfulExt\nusing Unitful\nimport ConstructionBase: constructorof\n\nconstructorof(::Type{Unitful.Quantity{_,D,U}}) where {_,D,U} =\n    Unitful.Quantity{T,D,U} where T\n\nend\n"
  },
  {
    "path": "ext/ForwardDiffExt.jl",
    "content": "module ForwardDiffExt\nusing Unitful\nusing ForwardDiff\n\nfunction Base.convert(d::Type{ForwardDiff.Dual{T, V, N}}, q::Quantity{T2, NoDims}) where {T, V, N, T2}\n    return d(uconvert(NoUnits, q))\nend\n\nend\n"
  },
  {
    "path": "ext/InverseFunctionsUnitfulExt.jl",
    "content": "module InverseFunctionsUnitfulExt\nusing Unitful\nimport InverseFunctions: inverse\n\n# `true` plays the role of 1, but doesn't promote unnecessary\ninverse(f::Base.Fix1{typeof(ustrip), <:Unitful.Units}) = Base.Fix1(*, true*f.x)\n\nend\n"
  },
  {
    "path": "ext/LatexifyExt.jl",
    "content": "#=========================================#\n# Extension for Unitful.jl + Latexify.jl, #\n# based on UnitfulLatexify.jl by          #\n# David Gustavsson (@gustaphe)            #\n#=========================================#\nmodule LatexifyExt\nusing Unitful:\n    Unitful,\n    Unit,\n    Units,\n    AbstractQuantity,\n    AffineUnits,\n    AffineQuantity,\n    power,\n    abbr,\n    name,\n    tens,\n    sortexp,\n    unit,\n    NoDims,\n    ustrip,\n    @u_str,\n    genericunit,\n    has_unit_spacing\nusing Latexify:\n    Latexify,\n    @latexrecipe,\n    latexify,\n    _latexarray,\n    latexraw,\n    FancyNumberFormatter,\n    PlainNumberFormatter,\n    StyledNumberFormatter,\n    SiunitxNumberFormatter,\n    AbstractNumberFormatter\nusing LaTeXStrings: LaTeXString\n\nimport Latexify: latexify\n\nimport Base.*\n\n# utility functions ------------------\n\nfunction get_formatter(kwargs)\n    fmt = get(kwargs, :fmt, FancyNumberFormatter())\n    if fmt isa String\n        fmt = StyledNumberFormatter(fmt)\n    end\n    return fmt\nend\nget_format_env(fmt::SiunitxNumberFormatter) = :raw\nget_format_env(fmt) = :inline\n\n\nfunction getunitname(p::T, unitformat) where {T<:Unit}\n    unitname = get(unitnames, (unitformat, name(p)), nothing)\n    isnothing(unitname) || return unitname\n    if unitformat === :siunitx\n        return \"\\\\$(lowercase(String(name(p))))\"\n    end\n    return abbr(p)\nend\n\nfunction listunits(::T) where {T<:Units}\n    return sortexp(T.parameters[1])\nend\n\n\"\"\"\n```julia\nintersperse(t, delim)\n```\nCreate a vector whose elements alternate between the elements of `t` and `delim`, analogous\nto `join` for strings.\n\n# Example\n```julia\njulia> intersperse((1, 2, 3, 4), :a)\n[1, :a, 2, :a, 3, :a, 4]\n```\n\"\"\"\nfunction intersperse(t::T, delim::U) where {T,U}\n    iszero(length(t)) && return ()\n    L = length(t) * 2 - 1\n    out = Vector{Union{typeof.(t)...,U}}(undef, L)\n    out[1:2:L] .= t\n    out[2:2:L] .= delim\n    return out\nend\n\n# default ------------------------------\n\n@latexrecipe function f(p::Unit)\n    fmt = get_formatter(kwargs)\n    env --> get_format_env(fmt)\n    return _transform(p, fmt)\nend\n\n@latexrecipe function f(u::Units; permode=:power)\n    fmt = get_formatter(kwargs)\n    env --> get_format_env(fmt)\n    return _transform(u, fmt)\nend\n\n@latexrecipe function f(q::AbstractQuantity)\n    fmt = get_formatter(kwargs)\n    env --> get_format_env(fmt)\n    operation := :*\n\n    return _transform(q, fmt)\nend\n\nstruct NakedUnits\n    u::Units\nend\nstruct NakedNumber\n    n::Number\nend\n\n@latexrecipe function f(u::NakedUnits; permode=:power)\n    fmt = get_formatter(kwargs)\n    unitlist = listunits(u.u)\n    if fmt isa SiunitxNumberFormatter\n        fmt.simple && return Expr(:latexifymerge, intersperse(unitlist, \".\")...)\n        return Expr(:latexifymerge, unitlist...)\n    end\n    if permode === :power\n        return Expr(:latexifymerge, intersperse(unitlist, \"\\\\,\")...)\n    end\n\n    numunits = [x for x in unitlist if power(x) >= 0]\n    denunits = [typeof(x)(tens(x), -power(x)) for x in unitlist if power(x) < 0]\n\n    numerator = intersperse(numunits, \"\\\\,\")\n    if isempty(denunits)\n        return Expr(:latexifymerge, numerator...)\n    end\n    if isempty(numunits)\n        numerator = [1]\n    end\n    denominator = intersperse(denunits, \"\\\\,\")\n\n    if permode === :slash\n        return Expr(:latexifymerge, numerator..., \"\\\\,/\\\\,\", denominator...)\n    end\n    if permode === :frac\n        return Expr(:latexifymerge, \"\\\\frac{\", numerator..., \"}{\", denominator..., \"}\")\n    end\n    return error(\"permode $permode undefined.\")\nend\n\n@latexrecipe function f(n::NakedNumber)\n    fmt = get_formatter(kwargs)\n    if fmt isa SiunitxNumberFormatter\n        fmt := PlainNumberFormatter()\n    end\n    return n.n\nend\n\nfunction _transform(p::Unit, fmt::SiunitxNumberFormatter)\n    unitformat = fmt.simple ? :siunitxsimple : :siunitx\n    prefix = prefixes[(unitformat, tens(p))]\n    pow = power(p)\n    unitname = getunitname(p, unitformat)\n    if fmt.simple\n        per = \"\"\n        expo = pow == 1//1 ? \"\" : \"^{$(latexify(pow; fmt=\"%g\", env=:raw))}\"\n    else\n        per = pow < 0 ? \"\\\\per\" : \"\"\n        pow = abs(pow)\n        expo = pow == 1//1 ? \"\" : \"\\\\tothe{$(latexify(pow; fmt=\"%g\", env=:raw))}\"\n    end\n    return LaTeXString(\"$per$prefix$unitname$expo\")\nend\nfunction _transform(p::Unit, fmt::AbstractNumberFormatter)\n    prefix = prefixes[(:mathrm, tens(p))]\n    unitname = getunitname(p, :mathrm)\n    pow = power(p)\n    expo = pow == 1//1 ? \"\" : \"^{$(latexify(pow; fmt=\"%g\", env=:raw))}\"\n    return LaTeXString(\"\\\\mathrm{$prefix$unitname}$expo\")\nend\n\nfunction _transform(u::Units, fmt::SiunitxNumberFormatter)\n    opening = fmt.version < 3 ? \"\\\\si{\" : \"\\\\unit{\"\n    return Expr(:latexifymerge, opening, NakedUnits(u), \"}\")\nend\n_transform(u::Units, ::AbstractNumberFormatter) = Expr(:latexifymerge, NakedUnits(u))\n\nfunction _transform(q::AbstractQuantity, fmt::SiunitxNumberFormatter)\n    opening = fmt.version < 3 ? \"\\\\SI{\" : \"\\\\qty{\"\n    return Expr(:latexifymerge, opening, NakedNumber(q.val), \"}{\", NakedUnits(unit(q)), \"}\")\nend\nfunction _transform(q::AbstractQuantity, ::AbstractNumberFormatter)\n    Expr(\n        :latexifymerge,\n        NakedNumber(q.val),\n        has_unit_spacing(unit(q)) ? \"\\\\,\" : nothing,\n        NakedUnits(unit(q)),\n    )\nend\n_transform(n::NakedNumber, ::SiunitxNumberFormatter) = PlainNumberFormatter(n.n)\n\n\n# affine -------------------------------\n\n@latexrecipe function f(u::AffineUnits)\n    fmt = get_formatter(kwargs)\n    if u == Unitful.°C\n        unitname = :Celsius\n    elseif u == Unitful.°F\n        unitname = :Fahrenheit\n    else\n        # If it's not celsius or farenheit, let it do the default thing\n        return genericunit(u)\n    end\n    if fmt isa SiunitxNumberFormatter\n        env --> :raw\n        return Expr(:latexifymerge, \"\\\\unit{\", unitnames[(:siunitx, unitname)], \"}\")\n    end\n    env --> :inline\n    return Expr(:latexifymerge, \"\\\\mathrm{\", unitnames[(:mathrm, unitname)], \"}\")\nend\n\n@latexrecipe function f(q::AffineQuantity)\n    fmt = get_formatter(kwargs)\n    u = unit(q)\n    if u == Unitful.°C\n        unitname = :Celsius\n    elseif u == Unitful.°F\n        unitname = :Fahrenheit\n    else\n        # If it's not celsius or farenheit, let it do the default thing\n        return ustrip(q)*genericunit(u)\n    end\n    if fmt isa SiunitxNumberFormatter\n        env --> :raw\n        return Expr(\n            :latexifymerge,\n            \"\\\\qty{\",\n            NakedNumber(q.val),\n            \"}{\",\n            unitnames[(:siunitx, unitname)],\n            \"}\",\n        )\n    end\n    env --> :inline\n    return Expr(:latexifymerge, q.val, \"\\\\,\\\\mathrm{\", unitnames[(:mathrm, unitname)], \"}\")\nend\n\n# arrays ------------------------- \n@latexrecipe function f( # Array{Quantity{U}}\n    a::AbstractArray{<:AbstractQuantity{N,D,U}};\n) where {N<:Number,D,U}\n    # Array of quantities with the same unit\n    env --> :equation\n    return Expr(\n        :latexifymerge, ustrip.(a), has_unit_spacing(first(a)) ? \"\\\\,\" : \"\", unit(first(a))\n    )\nend\n\n@latexrecipe function f( # Tuple{Quantity{U}}\n    l::Tuple{T,Vararg{T}},\n) where {T<:AbstractQuantity{N,D,U}} where {N<:Number,D,U}\n    fmt = get_formatter(kwargs)\n    if fmt isa SiunitxNumberFormatter\n        env --> :raw\n        opening = fmt.version < 3 ? \"\\\\SIlist{\" : \"\\\\qtylist{\"\n        return Expr(\n            :latexifymerge,\n            opening,\n            intersperse(NakedNumber.(ustrip.(l)), \";\")...,\n            \"}{\",\n            NakedUnits(unit(first(l))),\n            \"}\",\n        )\n    end\n    return collect(l)\nend\n\n# label (for plots) ------------------------------------\n\n@latexrecipe function f(l::AbstractString, u::Units; labelformat=:slash)\n    labelformat === :slash && return Expr(:latexifymerge, l, \"\\\\;\\\\left/\\\\;\", u, \"\\\\right.\")\n    labelformat === :square && return Expr(:latexifymerge, l, \"\\\\;\\\\left[\", u, \"\\\\right]\")\n    labelformat === :round && return Expr(:latexifymerge, l, \"\\\\;\\\\left(\", u, \"\\\\right)\")\n    labelformat === :frac && return Expr(:latexifymerge, \"\\\\frac{\", l, \"}{\", u, \"}\")\n    error(\"Unknown labelformat $labelformat\")\nend\n\n# prefixes ------------------------------\n\n\"\"\"\nprefixes are listed in this dictionary\n`(unitformat::Symbol, pow::Integer) => prefix::String`\n\"\"\"\nconst prefixes = begin\n    Dict(\n        (:mathrm, -24) => \"y\",\n        (:mathrm, -21) => \"z\",\n        (:mathrm, -18) => \"a\",\n        (:mathrm, -15) => \"f\",\n        (:mathrm, -12) => \"p\",\n        (:mathrm, -9) => \"n\",\n        (:mathrm, -6) => \"\\\\mu{}\",\n        (:mathrm, -3) => \"m\",\n        (:mathrm, -2) => \"c\",\n        (:mathrm, -1) => \"d\",\n        (:mathrm, 0) => \"\",\n        (:mathrm, 1) => \"D\",\n        (:mathrm, 2) => \"h\",\n        (:mathrm, 3) => \"k\",\n        (:mathrm, 6) => \"M\",\n        (:mathrm, 9) => \"G\",\n        (:mathrm, 12) => \"T\",\n        (:mathrm, 15) => \"P\",\n        (:mathrm, 18) => \"E\",\n        (:mathrm, 21) => \"Z\",\n        (:mathrm, 24) => \"Y\",\n        (:siunitx, -24) => \"\\\\yocto\",\n        (:siunitx, -21) => \"\\\\zepto\",\n        (:siunitx, -18) => \"\\\\atto\",\n        (:siunitx, -15) => \"\\\\femto\",\n        (:siunitx, -12) => \"\\\\pico\",\n        (:siunitx, -9) => \"\\\\nano\",\n        (:siunitx, -6) => \"\\\\micro\",\n        (:siunitx, -3) => \"\\\\milli\",\n        (:siunitx, -2) => \"\\\\centi\",\n        (:siunitx, -1) => \"\\\\deci\",\n        (:siunitx, 0) => \"\",\n        (:siunitx, 1) => \"\\\\deka\",\n        (:siunitx, 2) => \"\\\\hecto\",\n        (:siunitx, 3) => \"\\\\kilo\",\n        (:siunitx, 6) => \"\\\\mega\",\n        (:siunitx, 9) => \"\\\\giga\",\n        (:siunitx, 12) => \"\\\\tera\",\n        (:siunitx, 15) => \"\\\\peta\",\n        (:siunitx, 18) => \"\\\\exa\",\n        (:siunitx, 21) => \"\\\\zetta\",\n        (:siunitx, 24) => \"\\\\yotta\",\n        (:siunitxsimple, -24) => \"y\",\n        (:siunitxsimple, -21) => \"z\",\n        (:siunitxsimple, -18) => \"a\",\n        (:siunitxsimple, -15) => \"f\",\n        (:siunitxsimple, -12) => \"p\",\n        (:siunitxsimple, -9) => \"n\",\n        (:siunitxsimple, -6) => \"\\\\u\",\n        (:siunitxsimple, -3) => \"m\",\n        (:siunitxsimple, -2) => \"c\",\n        (:siunitxsimple, -1) => \"d\",\n        (:siunitxsimple, 0) => \"\",\n        (:siunitxsimple, 1) => \"D\",\n        (:siunitxsimple, 2) => \"h\",\n        (:siunitxsimple, 3) => \"k\",\n        (:siunitxsimple, 6) => \"M\",\n        (:siunitxsimple, 9) => \"G\",\n        (:siunitxsimple, 12) => \"T\",\n        (:siunitxsimple, 15) => \"P\",\n        (:siunitxsimple, 18) => \"E\",\n        (:siunitxsimple, 21) => \"Z\",\n        (:siunitxsimple, 24) => \"Y\",\n    )\nend\n\n# unit names ------------------------------\n\n\"\"\"\"\n`unitnames`\n\nUnit names generally follow a simple scheme, but there are exceptions, listed in this\ndictionary: `(unitformat::Symbol, name::Symbol) => unitname::String`\n\"\"\"\nconst unitnames = begin\n    Dict(\n        (:mathrm, :Percent) => \"\\\\%\",\n        (:siunitxsimple, :Percent) => \"\\\\%\",\n        (:mathrm, :Degree) => \"^{\\\\circ}\",\n        (:siunitxsimple, :Degree) => \"\\\\degree\",\n        (:siunitx, :eV) => \"\\\\electronvolt\",\n        (:mathrm, :Ohm) => \"\\\\Omega\",\n        (:mathrm, :Celsius) => \"^\\\\circ C\",\n        (:siunitx, :Celsius) => \"\\\\celsius\",\n        (:siunitxsimple, :Celsius) => \"\\\\celsius\",\n        (:mathrm, :Fahrenheit) => \"^\\\\circ F\",\n        (:siunitx, :Fahrenheit) => \"\\\\fahrenheit\",\n        (:siunitxsimple, :Fahrenheit) => \"\\\\fahrenheit\",\n        (:siunitxsimple, :Angstrom) => \"\\\\angstrom\",\n        (:mathrm, :Angstrom) => \"\\\\AA\",\n        (:mathrm, :DoubleTurn) => \"\\\\S\",\n        (:mathrm, :Turn) => \"\\\\tau\",\n        (:mathrm, :HalfTurn) => \"\\\\pi\",\n        (:mathrm, :Quadrant) => \"\\\\frac{\\\\pi}{2}\",\n        (:mathrm, :Sextant) => \"\\\\frac{\\\\pi}{3}\",\n        (:mathrm, :Octant) => \"\\\\frac{\\\\pi}{4}\",\n        (:mathrm, :ClockPosition) => \"\\\\frac{\\\\pi}{12}\",\n        (:mathrm, :HourAngle) => \"\\\\frac{\\\\pi}{24}\",\n        (:mathrm, :CompassPoint) => \"\\\\frac{\\\\pi}{32}\",\n        (:mathrm, :Hexacontade) => \"\\\\frac{\\\\pi}{60}\",\n        (:mathrm, :BinaryRadian) => \"\\\\frac{\\\\pi}{256}\",\n        (:mathrm, :DiameterPart) => \"\\\\oslash\", # This is slightly wrong\n        (:mathrm, :Gradian) => \"^g\",\n        (:mathrm, :Arcminute) => \"'\",\n        (:mathrm, :Arcsecond) => \"''\",\n        (:mathrm, :ArcsecondShort) => \"''\",\n    )\nend\n\nend # LatexifyExt"
  },
  {
    "path": "ext/NaNMathExt.jl",
    "content": "module NaNMathExt\nusing Unitful\nimport NaNMath\n\nNaNMath.sqrt(q::Unitful.AbstractQuantity) = NaNMath.sqrt(ustrip(q))*sqrt(unit(q))\nNaNMath.pow(q::Unitful.AbstractQuantity, r) = NaNMath.pow(ustrip(q), r)*unit(q)^r\nend\n"
  },
  {
    "path": "ext/PrintfExt.jl",
    "content": "module PrintfExt\n\nusing Printf\nusing Unitful\nusing Unitful: AbstractQuantity\n\nPrintf.plength(f::Printf.Spec{<:Printf.Ints}, x::AbstractQuantity{<:Real}) = Printf.plength(f, ustrip(x)) + length(string(unit(x))) + Unitful.has_unit_spacing(unit(x))\n\n# separate methods for disambiguation\nPrintf.fmt(buf, pos, arg::AbstractQuantity{<:Real}, spec::Printf.Spec{<:Printf.Floats}) = _fmt(buf, pos, arg, spec)\nPrintf.fmt(buf, pos, arg::AbstractQuantity{<:Real}, spec::Printf.Spec{<:Printf.Ints}) = _fmt(buf, pos, arg, spec)\n\nfunction _fmt(buf, pos, arg, spec)\n    pos = Printf.fmt(buf, pos, ustrip(arg), spec)\n    if Unitful.has_unit_spacing(unit(arg))\n        pos = Printf.fmt(buf, pos, ' ', only((Printf.format\"%c\").formats))\n    end\n    pos = Printf.fmt(buf, pos, string(unit(arg)), only((Printf.format\"%s\").formats))\n    return pos\nend\n\nend\n"
  },
  {
    "path": "src/Unitful.jl",
    "content": "module Unitful\n\nimport Base: ==, <, <=, +, -, *, /, //, ^, isequal, hash\nimport Base: show, convert\nimport Base: abs, abs2, angle, big, float, fma, muladd, inv, sqrt, cbrt\nimport Base: min, max, floor, ceil, real, imag, conj\nimport Base: complex, widen, reim # handled in complex.jl\nimport Base: exp, exp10, exp2, expm1, log, log10, log1p, log2\nimport Base: sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh,\n             sinpi, cospi, sinc, cosc, cis, cispi, sincos\nimport Base: eps, mod, rem, div, fld, cld, divrem, trunc, round, sign, signbit\nimport Base: isless, isapprox, isinteger, isreal, isinf, isfinite, isnan\nimport Base: iseven, isodd\nimport Base: copysign, flipsign\nimport Base: prevfloat, nextfloat, maxintfloat, rat, step\nimport Base: length, float, last, one, oneunit, zero, range\nimport Base: getindex, eltype, step, last, first, frexp\nimport Base: Integer, Rational, typemin, typemax\nimport Base: steprange_last, unsigned\nimport Base: sleep\n@static if VERSION ≥ v\"1.7.0-DEV.119\"\n    import Base: isunordered\nend\n\nimport Dates\nimport LinearAlgebra: Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal\nimport LinearAlgebra: istril, istriu, norm\nimport Random\n\nexport logunit, unit, absoluteunit, dimension, uconvert, ustrip, upreferred\nexport @dimension, @derived_dimension, @refunit, @unit, @affineunit, @u_str\nexport Quantity, DimensionlessQuantity, NoUnits, NoDims\n\nexport uconvertp, uconvertrp, reflevel, linear\nexport @logscale, @logunit, @dB, @B, @cNp, @Np\nexport Level, Gain\nexport uparse\n\nconst unitmodules = Vector{Module}()\n\nfunction _basefactors(m::Module)\n    # A hidden symbol which will be automatically attached to any module\n    # defining units, allowing `Unitful.register()` to merge in the units from\n    # that module.\n    basefactors_name = Symbol(\"#Unitful_basefactors\")\n    if isdefined(m, basefactors_name)\n        # It's not guaranteed that a world age update happened since the hidden\n        # symbol was added to another module, so use `invokelatest` to avoid #781.\n        Base.invokelatest(getproperty, m, basefactors_name)\n    else\n        Core.eval(m, :(const $basefactors_name = Dict{Symbol,Tuple{Float64,Rational{Int}}}()))\n    end\nend\n\nconst basefactors = _basefactors(Unitful)\n\ninclude(\"types.jl\")\nconst promotion = Dict{Symbol,FreeUnits}()\n\ninclude(\"user.jl\")\ninclude(\"utils.jl\")\ninclude(\"dimensions.jl\")\ninclude(\"units.jl\")\ninclude(\"quantities.jl\")\ninclude(\"display.jl\")\ninclude(\"promotion.jl\")\ninclude(\"conversion.jl\")\ninclude(\"range.jl\")\ninclude(\"fastmath.jl\")\ninclude(\"logarithm.jl\")\ninclude(\"complex.jl\")\ninclude(\"pkgdefaults.jl\")\ninclude(\"dates.jl\")\n\nif !isdefined(Base, :get_extension)\n    include(\"../ext/ConstructionBaseUnitfulExt.jl\")\n    include(\"../ext/InverseFunctionsUnitfulExt.jl\")\nend\n\nend\n"
  },
  {
    "path": "src/complex.jl",
    "content": "# This file is meant to provide all the methods in\n# https://github.com/JuliaLang/julia/blob/master/base/complex.jl that\n# are defined for Real or Complex numbers, just for\n# AbstractQuantities{T,D,U} where T is Real or Complex, respectively.\n#\n# It is currently incomplete.\n\ncomplex(z::Quantity{T,D,U}) where {T<:Complex,D,U} = z\nfunction complex(x::Quantity{T}, y = zero(x)) where {T<:Real}\n    r, i = promote(x, y)\n    return Quantity(complex(ustrip(r), ustrip(i)), unit(r))\nend\ncomplex(::Type{Quantity{T,D,U}}) where {T,D,U} =\n    Quantity{complex(T),D,U}\n\n# implement Base.widen for real and complex quantities because Unitful\n# does not have an implementation for widen yet\nBase.widen(::Type{Quantity{T,D,U}}) where {T,D,U} =\n    Quantity{widen(T),D,U}\n\n# skip Base.float, Base.real, Base.imag because it is already\n# implemented\n\n# Base.real for types has a general implementation in julia; a faster\n# method could be provided but is not strictly required.\n\n# Base.isreal, etc., are already implemented in Unitful.\n\n# Base.flipsign is already implemented in Unitful.\n\n# To Do: Check if Base.show, Base.read, Base.write, etc. need any\n#        attention\n\n# ...\n"
  },
  {
    "path": "src/conversion.jl",
    "content": "\"\"\"\n    convfact(s::Units, t::Units)\nFind the conversion factor from unit `t` to unit `s`, e.g., `convfact(m, cm) == 1//100`.\n\"\"\"\n@generated function convfact(s::Units, t::Units)\n    # Check if conversion is possible in principle\n    dimension(s()) != dimension(t()) && throw(DimensionError(s(), t()))\n\n    # use absoluteunit because division is invalid for AffineUnits;\n    # convert to FreeUnits first because absolute ContextUnits might still\n    # promote to AffineUnits\n    conv_units = absoluteunit(FreeUnits(t())) / absoluteunit(FreeUnits(s()))\n    inex, ex = basefactor(conv_units)\n    pow = tensfactor(conv_units)\n    inex_orig = inex\n\n    fpow = 10.0^pow\n    if fpow > typemax(Int) || 1/fpow > typemax(Int)\n        inex *= fpow\n    else\n        comp = (pow > 0 ? fpow * numerator(ex) : 1/fpow * denominator(ex))\n        if comp > typemax(Int)\n            inex *= fpow\n        else\n            ex *= (10//1)^pow\n        end\n    end\n\n    if ex isa Rational && denominator(ex) == 1\n        ex = numerator(ex)\n    end\n\n    result = (inex ≈ 1.0 ? 1 : inex) * ex\n    if fp_overflow_underflow(inex_orig, result)\n        throw(ArgumentError(\n            \"Floating point overflow/underflow, probably due to large \" *\n            \"exponents and/or SI prefixes in units\"\n        ))\n    end\n    return :($result)\nend\n\n\"\"\"\n    convfact{S}(s::Units{S}, t::Units{S})\nReturns 1. (Avoids effort when unnecessary.)\n\"\"\"\nconvfact(s::Units{S}, t::Units{S}) where {S} = 1\n\n\"\"\"\n    convfact(T::Type, s::Units, t::Units)\nReturns the appropriate conversion factor from unit `t` to unit `s` for the number type `T`.\n\"\"\"\nfunction convfact(::Type{T}, s::Units, t::Units) where T\n    cf = convfact(s, t)\n    if cf isa AbstractFloat\n        F = convfact_floattype(T)\n        # Since conversion factors only have Float64 precision,\n        # there is no point in converting to BigFloat\n        convert(F == BigFloat ? Float64 : F, cf)\n    else\n        cf\n    end\nend\n\nfunction convfact_floattype(::Type{T}) where T\n    # Use try-catch instead of hasmethod because a\n    # fallback method might exist but throw an error\n    try\n        _convfact_floattype(float(real(T)))\n    catch\n        Float64\n    end\nend\n\n_convfact_floattype(::Type) = Float64\n_convfact_floattype(::Type{Float16}) = Float16\n_convfact_floattype(::Type{Float32}) = Float32\n\n\"\"\"\n    uconvert(a::Units, x::Quantity{T,D,U}) where {T,D,U}\nConvert a [`Unitful.Quantity`](@ref) to different units. The conversion will\nfail if the target units `a` have a different dimension than the dimension of\nthe quantity `x`. You can use this method to switch between equivalent\nrepresentations of the same unit, like `N m` and `J`.\n\nExample:\n\n```jldoctest\njulia> uconvert(u\"hr\",3602u\"s\")\n1801//1800 hr\n\njulia> uconvert(u\"J\",1.0u\"N*m\")\n1.0 J\n```\n\"\"\"\nfunction uconvert(a::Units, x::Quantity{T,D,U}) where {T,D,U}\n    if typeof(a) == U\n        return Quantity(x.val, a)    # preserves numeric type if convfact is 1\n    elseif (a isa AffineUnits) || (x isa AffineQuantity)\n        return uconvert_affine(a, x)\n    else\n        return Quantity(x.val * convfact(T, a, U()), a)\n    end\nend\n\nfunction uconvert(a::Units, x::Number)\n    if dimension(a) == NoDims\n        Quantity(x * convfact(a, NoUnits), a)\n    else\n        throw(DimensionError(a,x))\n    end\nend\n\nuconvert(a::Units, x::Missing) = missing\n\n@generated function uconvert_affine(a::Units, x::Quantity)\n    # TODO: test, may be able to get bad things to happen here when T<:LogScaled\n    auobj = a()\n    xuobj = x.parameters[3]()\n    conv = convfact(auobj, xuobj)\n\n    t0 = x <: AffineQuantity ? x.parameters[3].parameters[end].parameters[end] :\n        :(zero($(x.parameters[1])))\n    t1 = a <: AffineUnits ? a.parameters[end].parameters[end] :\n        :(zero($(x.parameters[1])))\n    quote\n        dimension(a) != dimension(x) && throw(DimensionError(a, x))\n        return Quantity(((x.val - $t0) * $conv) + $t1, a)\n    end\nend\n\nfunction convert(::Type{Quantity{T,D,U}}, x::Number) where {T,D,U}\n    (dimension(x) != D) && throw(DimensionError(U(), x))\n    q = uconvert(U(), x)\n    Quantity{T,D,U}(isa(q, AbstractQuantity) ? q.val : q)\nend\n\n# needed ever since julialang/julia#28216\nconvert(::Type{Quantity{T,D,U}}, x::Quantity{T,D,U}) where {T,D,U} = x\n\nfunction convert(::Type{Quantity{T,D}}, x::Quantity) where {T,D}\n    (dimension(x) !== D) && throw(DimensionError(D, x))\n    return Quantity{T,D,typeof(unit(x))}(convert(T, x.val))\nend\nfunction convert(::Type{Quantity{T,D}}, x::Number) where {T,D}\n    (D !== NoDims) && throw(DimensionError(D, NoDims))\n    Quantity{T,NoDims,typeof(NoUnits)}(x)\nend\nfunction convert(::Type{Quantity{T}}, x::Quantity) where {T}\n    Quantity{T,dimension(x),typeof(unit(x))}(convert(T, x.val))\nend\nfunction convert(::Type{Quantity{T}}, x::Number) where {T}\n    Quantity{T,NoDims,typeof(NoUnits)}(x)\nend\n\nconvert(::Type{DimensionlessQuantity{T,U}}, x::Number) where {T,U} =\n    uconvert(U(), convert(T,x))\nfunction convert(::Type{DimensionlessQuantity{T,U}}, x::Quantity) where {T,U}\n    if dimension(x) == NoDims\n        _Quantity(T(x.val), U())\n    else\n        throw(DimensionError(NoDims,x))\n    end\nend\n\nconvert(::Type{Number}, y::Quantity) = y\nconvert(::Type{T}, y::Quantity) where {T <: Real} =\n    T(uconvert(NoUnits, y))\nconvert(::Type{T}, y::Quantity) where {T <: Complex} =\n    T(uconvert(NoUnits, y))\n"
  },
  {
    "path": "src/dates.jl",
    "content": "# Conversion from and to types from the `Dates` stdlib\n\n# Dates.FixedPeriod\n\nfor (period, unit) = ((Dates.Week, wk), (Dates.Day, d), (Dates.Hour, hr),\n                      (Dates.Minute, minute), (Dates.Second, s), (Dates.Millisecond, ms),\n                      (Dates.Microsecond, μs), (Dates.Nanosecond, ns))\n    @eval unit(::Type{$period}) = $unit\n    @eval (::Type{$period})(x::AbstractQuantity) = $period(ustrip(unit($period), x))\nend\n\ndimension(p::Dates.FixedPeriod) = dimension(typeof(p))\ndimension(::Type{<:Dates.FixedPeriod}) = 𝐓\n\n\"\"\"\n    unit(x::Dates.FixedPeriod)\n    unit(x::Type{<:Dates.FixedPeriod})\n\nReturn the units that correspond to a particular period.\n\n# Examples\n\n```jldoctest\njulia> using Dates\n\njulia> unit(Second(15)) == u\"s\"\ntrue\n\njulia> unit(Hour) == u\"hr\"\ntrue\n```\n\"\"\"\nunit(p::Dates.FixedPeriod) = unit(typeof(p))\n\nnumtype(x::Dates.FixedPeriod) = numtype(typeof(x))\nnumtype(::Type{T}) where {T<:Dates.FixedPeriod} = Int64\n\nquantitytype(::Type{T}) where {T<:Dates.FixedPeriod} =\n    Quantity{numtype(T),dimension(T),typeof(unit(T))}\n\nustrip(p::Dates.FixedPeriod) = Dates.value(p)\n\n\"\"\"\n    Quantity(period::Dates.FixedPeriod)\n\nCreate a `Quantity` that corresponds to the given `period`. The numerical value of the\nresulting `Quantity` is of type `Int64`.\n\n# Example\n\n```jldoctest\njulia> using Dates: Second\n\njulia> Quantity(Second(5))\n5 s\n```\n\"\"\"\nQuantity(period::Dates.FixedPeriod) = Quantity(ustrip(period), unit(period))\n\nuconvert(u::Units, period::Dates.FixedPeriod) = uconvert(u, Quantity(period))\n\n(T::Type{<:AbstractQuantity})(period::Dates.FixedPeriod) = T(Quantity(period))\n\nconvert(T::Type{<:AbstractQuantity}, period::Dates.FixedPeriod) = T(period)\nconvert(T::Type{<:Dates.FixedPeriod}, x::AbstractQuantity) = T(x)\n\nround(T::Type{<:Dates.FixedPeriod}, x::AbstractQuantity, r::RoundingMode=RoundNearest) =\n    T(round(numtype(T), ustrip(unit(T), x), r))\nround(u::Units, period::Dates.FixedPeriod, r::RoundingMode=RoundNearest; kwargs...) =\n    round(u, Quantity(period), r; kwargs...)\nround(T::Type{<:Number}, u::Units, period::Dates.FixedPeriod, r::RoundingMode=RoundNearest;\n      kwargs...) = round(T, u, Quantity(period), r; kwargs...)\nround(T::Type{<:AbstractQuantity}, period::Dates.FixedPeriod, r::RoundingMode=RoundNearest;\n      kwargs...) = round(T, Quantity(period), r; kwargs...)\n\nfor (f, r) in ((:floor,:RoundDown), (:ceil,:RoundUp), (:trunc,:RoundToZero))\n    @eval $f(T::Type{<:Dates.FixedPeriod}, x::AbstractQuantity) = round(T, x, $r)\n    @eval $f(u::Units, period::Dates.FixedPeriod; kwargs...) =\n        round(u, period, $r; kwargs...)\n    @eval $f(T::Type{<:Number}, u::Units, period::Dates.FixedPeriod; kwargs...) =\n        round(T, u, period, $r; kwargs...)\n    @eval $f(T::Type{<:AbstractQuantity}, period::Dates.FixedPeriod; kwargs...) =\n        round(T, period, $r; kwargs...)\nend\n\nfor op = (:+, :-, :*, :/, ://, :fld, :cld, :mod, :rem, :atan,\n          :(==), :isequal, :<, :isless, :≤)\n    @eval $op(x::Dates.FixedPeriod, y::AbstractQuantity) = $op(Quantity(x), y)\n    @eval $op(x::AbstractQuantity, y::Dates.FixedPeriod) = $op(x, Quantity(y))\nend\nfor op = (:*, :/, ://)\n    @eval $op(x::Dates.FixedPeriod, y::Units) = $op(Quantity(x), y)\n    @eval $op(x::Units, y::Dates.FixedPeriod) = $op(x, Quantity(y))\nend\ndiv(x::Dates.FixedPeriod, y::AbstractQuantity, r...) = div(Quantity(x), y, r...)\ndiv(x::AbstractQuantity, y::Dates.FixedPeriod, r...) = div(x, Quantity(y), r...)\n\nisapprox(x::Dates.FixedPeriod, y::AbstractQuantity; kwargs...) =\n    isapprox(Quantity(x), y; kwargs...)\nisapprox(x::AbstractQuantity, y::Dates.FixedPeriod; kwargs...) =\n    isapprox(x, Quantity(y); kwargs...)\n\nfunction isapprox(x::AbstractArray{<:AbstractQuantity}, y::AbstractArray{T};\n                  kwargs...) where {T<:Dates.Period}\n    if isconcretetype(T)\n        y′ = reinterpret(quantitytype(T), y)\n    else\n        y′ = Quantity.(y)\n    end\n    isapprox(x, y′; kwargs...)\nend\nisapprox(x::AbstractArray{<:Dates.FixedPeriod}, y::AbstractArray{<:AbstractQuantity};\n         kwargs...) = isapprox(y, x; kwargs...)\n\nBase.promote_rule(::Type{Quantity{T,𝐓,U}}, ::Type{S}) where {T,U,S<:Dates.FixedPeriod} =\n    promote_type(Quantity{T,𝐓,U}, quantitytype(S))\n\n# Dates.CompoundPeriod\n\ndimension(p::Dates.CompoundPeriod) = dimension(typeof(p))\ndimension(::Type{<:Dates.CompoundPeriod}) = 𝐓\n\nuconvert(u::Units, period::Dates.CompoundPeriod) =\n    Quantity{promote_type(Int64,typeof(convfact(u,ns))),dimension(u),typeof(u)}(period)\n\ntry_uconvert(u::Units, period::Dates.CompoundPeriod) = nothing\nfunction try_uconvert(u::TimeUnits, period::Dates.CompoundPeriod)\n    T = Quantity{promote_type(Int64,typeof(convfact(u,ns))),dimension(u),typeof(u)}\n    val = zero(T)\n    for p in period.periods\n        p isa Dates.FixedPeriod || return nothing\n        val += T(p)\n    end\n    val\nend\n\n(T::Type{<:AbstractQuantity})(period::Dates.CompoundPeriod) =\n    mapreduce(T, +, period.periods, init=zero(T))\n\nconvert(T::Type{<:AbstractQuantity}, period::Dates.CompoundPeriod) = T(period)\n\nround(u::Units, period::Dates.CompoundPeriod, r::RoundingMode=RoundNearest; kwargs...) =\n    round(u, uconvert(u, period), r; kwargs...)\nround(T::Type{<:Number}, u::Units, period::Dates.CompoundPeriod,\n      r::RoundingMode=RoundNearest; kwargs...) =\n    round(T, u, uconvert(u, period), r; kwargs...)\nround(T::Type{<:AbstractQuantity}, period::Dates.CompoundPeriod,\n      r::RoundingMode=RoundNearest; kwargs...) =\n    round(T, T(period), r; kwargs...)\n\nfor (f, r) in ((:floor,:RoundDown), (:ceil,:RoundUp), (:trunc,:RoundToZero))\n    @eval $f(u::Units, period::Dates.CompoundPeriod; kwargs...) =\n        round(u, period, $r; kwargs...)\n    @eval $f(T::Type{<:Number}, u::Units, period::Dates.CompoundPeriod; kwargs...) =\n        round(T, u, period, $r; kwargs...)\n    @eval $f(T::Type{<:AbstractQuantity}, period::Dates.CompoundPeriod; kwargs...) =\n        round(T, period, $r; kwargs...)\nend\n\nfor op = (:fld, :cld, :atan, :<, :isless, :≤)\n    @eval $op(x::Dates.CompoundPeriod, y::AbstractQuantity) = $op(uconvert(unit(y),x), y)\n    @eval $op(x::AbstractQuantity, y::Dates.CompoundPeriod) = $op(x, uconvert(unit(x),y))\nend\ndiv(x::Dates.CompoundPeriod, y::AbstractQuantity, r...) = div(uconvert(unit(y),x), y, r...)\ndiv(x::AbstractQuantity, y::Dates.CompoundPeriod, r...) = div(x, uconvert(unit(x),y), r...)\nmod(x::Dates.CompoundPeriod, y::AbstractQuantity) = mod(uconvert(unit(y),x), y)\nrem(x::Dates.CompoundPeriod, y::AbstractQuantity) = rem(uconvert(unit(y),x), y)\nfor op = (:(==), :isequal)\n    @eval $op(x::Dates.CompoundPeriod, y::AbstractQuantity{T,𝐓,U}) where {T,U} =\n        $op(try_uconvert(U(), x), y)\n    @eval $op(x::AbstractQuantity{T,𝐓,U}, y::Dates.CompoundPeriod) where {T,U} =\n        $op(x, try_uconvert(U(), y))\nend\n\nisapprox(x::Dates.CompoundPeriod, y::AbstractQuantity; kwargs...) =\n    dimension(y) === 𝐓 ? isapprox(uconvert(unit(y), x), y; kwargs...) : false\nisapprox(x::AbstractQuantity, y::Dates.CompoundPeriod; kwargs...) =\n    dimension(x) === 𝐓 ? isapprox(x, uconvert(unit(x), y); kwargs...) : false\n\nfunction isapprox(x::AbstractArray{<:AbstractQuantity},\n                  y::AbstractArray{Dates.CompoundPeriod}; kwargs...)\n    if dimension(eltype(x)) === 𝐓\n        isapprox(x, uconvert.(unit(eltype(x)), y); kwargs...)\n    else\n        false\n    end\nend\n\nisapprox(x::AbstractArray{Dates.CompoundPeriod}, y::AbstractArray{<:AbstractQuantity};\n         kwargs...) = isapprox(y, x; kwargs...)\n\nsleep(x::AbstractQuantity) = sleep(ustrip(s, x))\n\n# Dates, Times, DateTimes\n\nfor f in (:+, :-)\n    @eval Base.$f(x::Dates.DateTime, y::Quantity) = $f(x, trunc(Dates.Millisecond, y))\n    @eval Base.$f(x::Dates.Time, y::Quantity) = $f(x, trunc(Dates.Nanosecond, y))\n    @eval Base.$f(x::Dates.Date, y::Quantity) = $f(x, Dates.Day(y))\nend\nBase.:+(y::Quantity, x::Dates.DateTime) = x + y\nBase.:+(y::Quantity, x::Dates.Time) = x + y\nBase.:+(y::Quantity, x::Dates.Date) = x + y\n"
  },
  {
    "path": "src/dimensions.jl",
    "content": "\"\"\"\n```\n*(a0::Dimensions, a::Dimensions...)\n```\n\nGiven however many dimensions, multiply them together.\n\nCollect [`Unitful.Dimension`](@ref) objects from the type parameter of the\n[`Unitful.Dimensions`](@ref) objects. For identical dimensions, collect powers\nand sort uniquely by the name of the `Dimension`.\n\nExamples:\n\n```jldoctest\njulia> u\"𝐌*𝐋/𝐓^2\"\n𝐋 𝐌 𝐓^-2\n\njulia> u\"𝐋*𝐌/𝐓^2\"\n𝐋 𝐌 𝐓^-2\n\njulia> typeof(u\"𝐋*𝐌/𝐓^2\") == typeof(u\"𝐌*𝐋/𝐓^2\")\ntrue\n```\n\"\"\"\n@generated function *(a0::Dimensions, a::Dimensions...)\n    # Implementation is very similar to *(::Units, ::Units...)\n    b = Vector{Dimension}()\n    a0p = a0.parameters[1]\n    length(a0p) > 0 && append!(b, a0p)\n    for x in a\n        xp = x.parameters[1]\n        length(xp) > 0 && append!(b, xp)\n    end\n\n    sort!(b, by=power)\n    sort!(b, by=name)\n\n    c = Vector{Dimension}()\n    if !isempty(b)\n        next = iterate(b)\n        p = 0//1\n        oldvalue = next[1]\n        while next !== nothing\n            (value, state) = next\n            if name(value) == name(oldvalue)\n                p += power(value)\n            else\n                if p != 0\n                    push!(c, Dimension{name(oldvalue)}(p))\n                end\n                p = power(value)\n            end\n            oldvalue = value\n            next = iterate(b, state)\n        end\n\n        if p != 0\n            push!(c, Dimension{name(oldvalue)}(p))\n        end\n    end\n\n    d = (c...,)\n    :(Dimensions{$d}())\nend\n\n/(x::Dimensions, y::Dimensions) = *(x,inv(y))\n//(x::Dimensions, y::Dimensions)  = x/y\n\n# Both methods needed for ambiguity resolution\n^(x::Dimension{T}, y::Integer) where {T} = Dimension{T}(power(x)*y)\n^(x::Dimension{T}, y::Number) where {T} = Dimension{T}(power(x)*y)\n\n# A word of caution:\n# Exponentiation is not type-stable for `Dimensions` objects in many cases\n^(x::Dimensions{T}, y::Integer) where {T} = *(Dimensions{map(a->a^y, T)}())\n^(x::Dimensions{T}, y::Number) where {T} = *(Dimensions{map(a->a^y, T)}())\n\n@generated function Base.literal_pow(::typeof(^), x::Dimensions{T}, ::Val{p}) where {T,p}\n    z = *(Dimensions{map(a->a^p, T)}())\n    :($z)\nend\n\n# Since exponentiation is not type stable, we define a special `inv` method to enable fast\n# division. For julia 0.6.0, the appropriate methods for ^ and * need to be defined before\n# this one!\nfor (fun,pow) in ((:inv, -1//1), (:sqrt, 1//2), (:cbrt, 1//3))\n    # The following are generated functions to ensure type stability.\n    @eval @generated function ($fun)(x::Dimensions)\n        dimtuple = map(x->x^($pow), x.parameters[1])\n        y = *(Dimensions{dimtuple}())    # sort appropriately\n        :($y)\n    end\nend\n"
  },
  {
    "path": "src/display.jl",
    "content": "# Convenient dictionary for mapping powers of ten to an SI prefix.\nconst prefixdict = Dict(\n    -24 => \"y\",\n    -21 => \"z\",\n    -18 => \"a\",\n    -15 => \"f\",\n    -12 => \"p\",\n    -9  => \"n\",\n    -6  => \"μ\",\n    -3  => \"m\",\n    -2  => \"c\",\n    -1  => \"d\",\n    0   => \"\",\n    1   => \"da\",\n    2   => \"h\",\n    3   => \"k\",\n    6   => \"M\",\n    9   => \"G\",\n    12  => \"T\",\n    15  => \"P\",\n    18  => \"E\",\n    21  => \"Z\",\n    24  => \"Y\"\n)\n\n\"\"\"\n    abbr(x)\nProvides abbreviations for units or dimensions. Since a method should\nalways be defined for each unit and dimension type, absence of a method for a\nspecific unit or dimension type is likely an error. Consequently, we return ❓\nfor generic arguments to flag unexpected behavior.\n\"\"\"\nabbr(x) = \"❓\"     # Indicate missing abbreviations\n\n\"\"\"\n    prefix(x::Unit)\nReturns a string representing the SI prefix for the power-of-ten held by\nthis particular unit.\n\"\"\"\nfunction prefix(x::Unit)\n    if haskey(prefixdict, tens(x))\n        return prefixdict[tens(x)]\n    else\n        error(\"Invalid power-of-ten prefix.\")\n    end\nend\n\nfunction show(io::IO, x::Unit{N,D}) where {N,D}\n    show(io, FreeUnits{(x,), D, nothing}())\nend\n\nabstract type BracketStyle end\n\nstruct NoBrackets <: BracketStyle end\nprint_opening_bracket(io::IO, ::NoBrackets) = nothing\nprint_closing_bracket(io::IO, ::NoBrackets) = nothing\n\nstruct RoundBrackets <: BracketStyle end\nprint_opening_bracket(io::IO, ::RoundBrackets) = print(io, '(')\nprint_closing_bracket(io::IO, ::RoundBrackets) = print(io, ')')\n\nstruct SquareBrackets <: BracketStyle end\nprint_opening_bracket(io::IO, ::SquareBrackets) = print(io, '[')\nprint_closing_bracket(io::IO, ::SquareBrackets) = print(io, ']')\n\nprint_opening_bracket(io::IO, x) = print_opening_bracket(io, BracketStyle(x))\nprint_closing_bracket(io::IO, x) = print_closing_bracket(io, BracketStyle(x))\n\n\"\"\"\n    BracketStyle(x)\n    BracketStyle(typeof(x))\n\n`BracketStyle` specifies whether the numeric value of a `Quantity` is printed in brackets\n(and what kind of brackets). Three styles are defined:\n\n* `NoBrackets()`: this is the default, for example used for real numbers: `1.2 m`\n* `RoundBrackets()`: used for complex numbers: `(2.5 + 1.0im) V`\n* `SquareBrackets()`: used for [`Level`](@ref)/[`Gain`](@ref): `[3 dB] Hz^-1`\n\"\"\"\nBracketStyle(x) = BracketStyle(typeof(x))\nBracketStyle(::Type) = NoBrackets()\nBracketStyle(::Type{<:Complex}) = RoundBrackets()\n\n\"\"\"\n    showval(io::IO, x::Number, brackets::Bool=true)\n\nShow the numeric value `x` of a quantity. Depending on the type of `x`, the value may be\nenclosed in brackets (see [`BracketStyle`](@ref)). If `brackets` is set to `false`, the\nbrackets are not printed.\n\"\"\"\nfunction showval(io::IO, x::Number, brackets::Bool=true)\n    brackets && print_opening_bracket(io, x)\n    show(io, x)\n    brackets && print_closing_bracket(io, x)\nend\n\nfunction showval(io::IO, mime::MIME, x::Number, brackets::Bool=true)\n    brackets && print_opening_bracket(io, x)\n    show(io, mime, x)\n    brackets && print_closing_bracket(io, x)\nend\n\n# Space between numerical value and unit should always be included\n# except for angular degrees, minutes and seconds (° ′ ″)\n# See SI 9th edition, section 5.4.3; \"Formatting the value of a quantity\"\n# https://www.bipm.org/utils/common/pdf/si-brochure/SI-Brochure-9.pdf\nhas_unit_spacing(u) = true\nhas_unit_spacing(u::Units{(Unit{:Degree, NoDims}(0, 1//1),), NoDims}) = false\n\n\"\"\"\n    show(io::IO, x::Quantity)\nShow a unitful quantity by calling [`showval`](@ref) on the numeric value, appending a\nspace, and then calling `show` on a units object `U()`.\n\"\"\"\nfunction show(io::IO, x::Quantity)\n    if isunitless(unit(x))\n        showval(io, x.val, false)\n    else\n        showval(io, x.val, true)\n        has_unit_spacing(unit(x)) && print(io, ' ')\n        show(io, unit(x))\n    end\nend\n\nfunction show(io::IO, mime::MIME\"text/plain\", x::Quantity)\n    if isunitless(unit(x))\n        showval(io, mime, x.val, false)\n    else\n        showval(io, mime, x.val, true)\n        has_unit_spacing(unit(x)) && print(io, ' ')\n        show(io, mime, unit(x))\n    end\nend\n\nfunction show(io::IO, r::StepRange{T}) where T<:Quantity\n    a,s,b = first(r), step(r), last(r)\n    U = unit(a)\n    V = absoluteunit(U)\n    print(io, '(')\n    if ustrip(V, s) == 1\n        show(io, ustrip(U, a):ustrip(U, b))\n    else\n        show(io, ustrip(U, a):ustrip(V, s):ustrip(U, b))\n    end\n    print(io, ')')\n    has_unit_spacing(U) && print(io,' ')\n    show(io, U)\nend\n\nfunction show(io::IO, r::StepRangeLen{T}) where T<:Quantity\n    a,s,b = first(r), step(r), last(r)\n    U = unit(a)\n    V = absoluteunit(U)\n    print(io, '(')\n    show(io, StepRangeLen(ustrip(U, a), ustrip(V, s), length(r)))\n    print(io, ')')\n    has_unit_spacing(U) && print(io,' ')\n    show(io, U)\nend\n\nfunction show(io::IO, x::typeof(NoDims))\n    print(io, \"NoDims\")\nend\n\n\"\"\"\n    show(io::IO, x::Unitlike)\nCall [`Unitful.showrep`](@ref) on each object in the tuple that is the type\nvariable of a [`Unitful.Units`](@ref) or [`Unitful.Dimensions`](@ref) object.\n\"\"\"\nfunction show(io::IO, x::Unitlike)\n    showoperators = get(io, :showoperators, false)\n    sep = showoperators ? \"*\" : \" \"\n    isfirst = true\n    for y in sortexp(x)\n        isfirst || print(io, sep)\n        showrep(io, y)\n        isfirst = false\n    end\n    nothing\nend\n\n\"\"\"\n    sortexp(xs)\nSort units to show positive exponents first.\n\"\"\"\nsortexp(xs) = sort!(collect(xs), by = u->signbit(power(u)), alg = InsertionSort)\n@generated sortexp(::Dimensions{D}) where D = (sortexp(D)...,)\n@generated sortexp(::Units{U}) where U = (sortexp(U)...,)\n\n\"\"\"\n    showrep(io::IO, x::Unit)\nShow the unit, prefixing with any decimal prefix and appending the exponent as\nformatted by [`Unitful.superscript`](@ref).\n\"\"\"\nfunction showrep(io::IO, x::Unit)\n    print(io, prefix(x))\n    print(io, abbr(x))\n    print(io, (power(x) == 1//1 ? \"\" : superscript(power(x); io=io)))\n    nothing\nend\n\n\"\"\"\n    showrep(io::IO, x::Dimension)\nShow the dimension, appending any exponent as formatted by\n[`Unitful.superscript`](@ref).\n\"\"\"\nfunction showrep(io::IO, x::Dimension)\n    print(io, abbr(x))\n    print(io, (power(x) == 1//1 ? \"\" : superscript(power(x); io=io)))\nend\n\n\"\"\"\n    superscript(i::Rational; io::Union{IO, Nothing} = nothing)\nReturns exponents as a string.\n\nThis function returns the value as a string. It does not print to `io`. `io` is\nonly used for IO context values. If `io` contains the `:fancy_exponent`\nproperty and the value is a `Bool`, this value will override the behavior of\nfancy exponents.\n\"\"\"\nfunction superscript(i::Rational; io::Union{IO, Nothing} = nothing)\n    if io === nothing\n        iocontext_value = nothing\n    else\n        iocontext_value = get(io, :fancy_exponent, nothing)\n    end\n    if iocontext_value isa Bool\n        fancy_exponent = iocontext_value\n    else\n        v = get(ENV, \"UNITFUL_FANCY_EXPONENTS\", Sys.isapple() ? \"true\" : \"false\")\n        t = tryparse(Bool, lowercase(v))\n        fancy_exponent = (t === nothing) ? false : t\n    end\n    if fancy_exponent\n        return i.den == 1 ? superscript(i.num) : string(superscript(i.num), '\\u141F', superscript(i.den))\n    else\n        i.den == 1 ? \"^\" * string(i.num) : \"^\" * replace(string(i), \"//\" => \"/\")\n    end\nend\n\n# Taken from SIUnits.jl\nsuperscript(i::Integer) = map(repr(i)) do c\n    c == '-' ? '\\u207b' :\n    c == '1' ? '\\u00b9' :\n    c == '2' ? '\\u00b2' :\n    c == '3' ? '\\u00b3' :\n    c == '4' ? '\\u2074' :\n    c == '5' ? '\\u2075' :\n    c == '6' ? '\\u2076' :\n    c == '7' ? '\\u2077' :\n    c == '8' ? '\\u2078' :\n    c == '9' ? '\\u2079' :\n    c == '0' ? '\\u2070' :\n    error(\"unexpected character\")\nend\n\nif isdefined(Base, :alignment_from_show)\n    printed_length(io, x) = Base.alignment_from_show(io, x)\nelse\n    printed_length(io, x) = length(sprint(show, x, context=io))\nend\n\nfunction Base.alignment(io::IO, x::Quantity)\n    if isunitless(unit(x))\n        return Base.alignment(io, x.val)\n    end\n    length = printed_length(io, x)\n    left, _ = Base.alignment(io, x.val)\n    left += BracketStyle(x.val) != NoBrackets()\n    return left, length - left\nend\n"
  },
  {
    "path": "src/fastmath.jl",
    "content": "import Base.FastMath\n\nimport Base.FastMath: @fastmath,\n    FloatTypes,\n    ComplexTypes,\n    add_fast,\n    sub_fast,\n    mul_fast,\n    div_fast,\n    rem_fast,\n    cmp_fast,\n    # mod_fast,\n    eq_fast,\n    ne_fast,\n    lt_fast,\n    le_fast,\n    pow_fast,\n    sqrt_fast,\n    cos_fast,\n    sin_fast,\n    tan_fast,\n    sincos_fast,\n    atan_fast,\n    hypot_fast,\n    max_fast,\n    min_fast,\n    minmax_fast,\n    cis_fast,\n    angle_fast,\n    fast_op\n\nsub_fast(x::Quantity{T}) where {T <: FloatTypes} = typeof(x)(sub_fast(x.val))\n\nadd_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n    Quantity{T,D,U}(add_fast(x.val, y.val))\n\nsub_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n    Quantity{T,D,U}(sub_fast(x.val, y.val))\n\nfunction mul_fast(x::Quantity{T}, y::Quantity{T}) where {T <: FloatTypes}\n    D = dimension(x) * dimension(y)\n    U = typeof(unit(x) * unit(y))\n    Quantity{T,D,U}(mul_fast(x.val, y.val))\nend\nfunction div_fast(x::Quantity{T}, y::Quantity{T}) where {T <: FloatTypes}\n    D = dimension(x) / dimension(y)\n    U = typeof(unit(x) / unit(y))\n    Quantity{T,D,U}(div_fast(x.val, y.val))\nend\n\nrem_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n    Quantity{T,D,U}(rem_fast(x.val, y.val))\n\nadd_fast(x::Quantity{T}, y::Quantity{T}, z::Quantity{T}, t::Quantity{T}...) where {T <: FloatTypes} =\n    add_fast(add_fast(add_fast(x, y), z), t...)\nmul_fast(x::Quantity{T}, y::Quantity{T}, z::Quantity{T}, t::Quantity{T}...) where {T <: FloatTypes} =\n    mul_fast(mul_fast(mul_fast(x, y), z), t...)\n\n@fastmath begin\n    cmp_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n        ifelse(x==y, 0, ifelse(x<y, -1, +1))\nend\n\neq_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n    eq_fast(x.val,y.val)\nne_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n    ne_fast(x.val,y.val)\nlt_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n    lt_fast(x.val,y.val)\nle_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n    le_fast(x.val,y.val)\n\n@fastmath begin\n    abs_fast(x::Quantity{T}) where {T <: ComplexTypes} = hypot(real(x), imag(x))\n    abs2_fast(x::Quantity{T}) where {T <: ComplexTypes} = real(x)*real(x) + imag(x)*imag(x)\n    conj_fast(x::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =\n        Quantity{T,D,U}(T(real(x.val), -imag(x.val)))\n    inv_fast(x::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} = conj(x) / abs2(x)\n    sign_fast(x::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =\n        x == Quantity(0, U()) ? float(zero(x)) : x/abs(x)\n\n    add_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =\n        Quantity{T,D,U}(T(real(x.val)+real(y.val), imag(x.val)+imag(y.val)))\n    add_fast(x::Quantity{Complex{T},D,U}, b::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)+b.val, imag(x.val)))\n    add_fast(a::Quantity{T,D,U}, y::Quantity{Complex{T},D,U}) where {T <: FloatTypes,D,U} =\n        Quantity{Complex{T},D,U}(Complex{T}(a.val+real(y.val), imag(y.val)))\n\n    sub_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =\n        Quantity{T,D,U}(T(real(x.val)-real(y.val), imag(x.val)-imag(y.val)))\n    sub_fast(x::Quantity{Complex{T},D,U}, b::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)-b.val, imag(x.val)))\n    sub_fast(a::Quantity{T,D,U}, y::Quantity{Complex{T},D,U}) where {T <: FloatTypes,D,U} =\n        Quantity{Complex{T},D,U}(Complex{T}(a.val-real(y.val), -imag(y.val)))\n\n    function mul_fast(x::Quantity{T}, y::Quantity{T}) where {T <: ComplexTypes}\n        D = dimension(x) * dimension(y)\n        U = typeof(unit(x) * unit(y))\n        Quantity{T,D,U}(T(real(x.val)*real(y.val) - imag(x.val)*imag(y.val),\n          real(x.val)*imag(y.val) + imag(x.val)*real(y.val)))\n    end\n    function mul_fast(x::Quantity{Complex{T}}, b::Quantity{T}) where {T <: FloatTypes}\n        D = dimension(x) * dimension(b)\n        U = typeof(unit(x) * unit(b))\n        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)*b.val, imag(x.val)*b.val))\n    end\n    function mul_fast(a::Quantity{T}, y::Quantity{Complex{T}}) where {T <: FloatTypes}\n        D = dimension(a) * dimension(y)\n        U = typeof(unit(a) * unit(y))\n        Quantity{Complex{T},D,U}(Complex{T}(a.val*real(y.val), a.val*imag(y.val)))\n    end\n\n    @inline function div_fast(x::Quantity{T}, y::Quantity{T}) where {T <: ComplexTypes}\n        D = dimension(x) * dimension(y)\n        U = typeof(unit(x) * unit(y))\n        Quantity{T,D,U}(T(real(x.val)*real(y.val) + imag(x.val)*imag(y.val),\n          imag(x.val)*real(y.val) - real(x.val)*imag(y.val))) / abs2(y)\n    end\n    function div_fast(x::Quantity{Complex{T}}, b::Quantity{T}) where {T <: FloatTypes}\n        D = dimension(x) / dimension(b)\n        U = typeof(unit(x) / unit(b))\n        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)/b.val, imag(x.val)/b.val))\n    end\n    function div_fast(a::Quantity{T}, y::Quantity{Complex{T}}) where {T <: FloatTypes}\n        D = dimension(a) * dimension(y)\n        U = typeof(unit(a) * unit(y))\n        Quantity{Complex{T},D,U}(Complex{T}(a.val*real(y.val),\n            -a.val*imag(y.val))) / abs2(y)\n    end\n\n    eq_fast(x::Quantity{T}, y::Quantity{T}) where {T <: ComplexTypes} =\n        (real(x)==real(y)) & (imag(x)==imag(y))\n    eq_fast(x::Quantity{Complex{T}}, b::Quantity{T}) where {T <: FloatTypes} =\n        (real(x)==b) & (imag(x)==zero(b))\n    eq_fast(a::Quantity{T}, y::Quantity{Complex{T}}) where {T <: FloatTypes} =\n        (a==real(y)) & (zero(a)==imag(y))\n\n    ne_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} = !(x==y)\nend\n\nfor op in (:+, :-, :*, :/, :(==), :!=, :<, :<=, :cmp, :rem)\n    op_fast = fast_op[op]\n    @eval begin\n        # Fallback method for Quantitys after promotion.\n        $op_fast(x::Quantity{T},ys::Quantity{T}...) where {T <: Number} = $op(x,ys...)\n    end\nend\n\n# exponentiation is not and cannot be type-stable for `Quantity`s,\n# so we will not fastmathify it\npow_fast(x::Quantity, y::Integer) = x^y\npow_fast(x::Quantity, y::Rational) = x^y\n\nsqrt_fast(x::Quantity{T}) where {T <: FloatTypes} =\n    Quantity(sqrt_fast(x.val), sqrt(unit(x)))\n\nfor f in (:cos, :sin, :tan, :sincos, :cis)\n    f_fast = fast_op[f]\n    @eval $f_fast(x::DimensionlessQuantity) = $f_fast(ustrip(NoUnits, x))\nend\n\natan_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T,D,U} =\n    atan_fast(x.val, y.val)\n\n@fastmath begin\n    hypot_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n        sqrt(x*x + y*y)\n\n    # Note: we use the same comparison for min, max, and minmax, so\n    # that the compiler can convert between them\n    max_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n        ifelse(y > x, y, x)\n    min_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n        ifelse(y > x, x, y)\n    minmax_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =\n        ifelse(y > x, (x,y), (y,x))\n\n    # complex numbers\n\n    angle_fast(x::Quantity{T}) where {T <: ComplexTypes} = atan(imag(x), real(x))\nend\n"
  },
  {
    "path": "src/logarithm.jl",
    "content": "base(::LogInfo{N,B}) where {N,B} = B\nprefactor(::LogInfo{N,B,P}) where {N,B,P} = P\nzero(x::T) where {T<:Level} = T(zero(x.val))\nzero(::Type{X}) where {L,S,T,X<:Level{L,S,T}} = X(zero(T))\none(x::T) where {T<:Level} = one(x.val)\none(::Type{X}) where {L,S,T,X<:Level{L,S,T}} = one(T)\nfunction Base.float(x::Level{L,S}) where {L,S}\n    v = float(x.val)\n    return Level{L,S,typeof(v)}(v)\nend\nbig(x::Level{L,S}) where {L,S} = Level{L,S}(big(x.val))\n\"\"\"\n    logunit(x::LogScaled)\n    logunit(x::Union{Type{<:LogScaled}, MixedUnits})\nReturns the logarithmic \"units\" associated with a `LogScaled` instance, a \n`LogScaled` type, or a `MixedUnits`.\n\nExamples:\n```jldoctest\njulia> using Unitful\n\njulia> logunit(1*u\"dB\")\ndB\n\njulia> logunit(u\"dB\")\ndB\n\njulia> logunit(u\"dB/s\")\ndB\n```\n\nSee also: [`unit`](@ref).\n\"\"\"\nfunction logunit end\nlogunit(x::Level{L,S}) where {L,S} = MixedUnits{Level{L,S}}()\nlogunit(x::Type{T}) where {L,S,T<:Level{L,S}} = MixedUnits{Level{L,S}}()\n\nabbr(x::Level{L,S}) where {L,S} = join([abbr(L()), \" (\", S, \")\"])\n\nBase.convert(::Type{LogScaled{L1}}, x::Level{L2,S}) where {L1,L2,S} = Level{L1,S}(x.val)\nBase.convert(T::Type{<:Level}, x::Level) = T(x.val)\nBase.convert(::Type{Quantity{T,D,U}}, x::Level) where {T,D,U} =\n    convert(Quantity{T,D,U}, x.val)\nBase.convert(::Type{Quantity{T}}, x::Level) where {T<:Number} = convert(Quantity{T}, x.val)\nBase.convert(::Type{T}, x::Quantity) where {L,S,T<:Level{L,S}} = T(x)\nBase.convert(::Type{T}, x::Level) where {T<:Real} = T(x.val)\n\nfunction Base.float(x::Gain{L,S}) where {L,S}\n    v = float(x.val)\n    return Gain{L,S,typeof(v)}(v)\nend\nbig(x::Gain{L,S}) where {L,S} = Gain{L,S}(big(x.val))\nlogunit(x::Gain{L,S}) where {L,S} = MixedUnits{Gain{L,S}}()\nlogunit(x::Type{T}) where {L,S, T<:Gain{L,S}} = MixedUnits{Gain{L,S}}()\nabbr(x::Gain{L}) where {L} = abbr(L())\nzero(x::T) where {T<:Gain} = T(zero(x.val))\nzero(::Type{X}) where {L,S,T, X<:Gain{L,S,T}} = X(zero(T))\none(x::T) where {T<:Gain} = T(zero(x.val))\none(::Type{X}) where {L,S,T, X<:Gain{L,S,T}} = X(zero(T))\nfunction Gain{L}(val::Real) where {L <: LogInfo}\n    dimension(val) != NoDims && throw(DimensionError(val,1))\n    return Gain{L, :?, typeof(val)}(val)\nend\nfunction Gain{L,S}(val::Real) where {L <: LogInfo,S}\n    dimension(val) != NoDims && throw(DimensionError(val,1))\n    return Gain{L, S, typeof(val)}(val)\nend\n\nBase.convert(::Type{Gain{L}}, x::Gain{L,S}) where {L,S} = Gain{L,S}(x.val)\nBase.convert(::Type{Gain{L1}}, x::Gain{L2,S}) where {L1,L2,S} = Gain{L1,S}(_gconv(L1,L2,x))\n\nBase.convert(::Type{Gain{L,S}}, x::Gain{L,S}) where {L,S} = Gain{L,S}(x.val)\nBase.convert(::Type{Gain{L1,S}}, x::Gain{L2,S}) where {L1,L2,S} = Gain{L1,S}(_gconv(L1,L2,x))\nBase.convert(::Type{Gain{L,S1}}, x::Gain{L,S2}) where {L,S1,S2} = Gain{L,S1}(x.val)\nBase.convert(::Type{Gain{L1,S1}}, x::Gain{L2,S2}) where {L1,L2,S1,S2} =\n    Gain{L1,S1}(_gconv(L1,L2,x))\n\nBase.convert(::Type{Gain{L,S,T}}, x::Gain{L,S}) where {L,S,T} = Gain{L,S,T}(x.val)\nBase.convert(::Type{Gain{L1,S,T}}, x::Gain{L2,S}) where {L1,L2,S,T} =\n    Gain{L1,S,T}(_gconv(L1,L2,x))\nBase.convert(::Type{Gain{L,S1,T}}, x::Gain{L,S2}) where {L,S1,S2,T} =\n    Gain{L,S1,T}(x.val)\nBase.convert(::Type{Gain{L1,S1,T}}, x::Gain{L2,S2}) where {L1,L2,S1,S2,T} =\n    Gain{L1,S1,T}(_gconv(L1,L2,x))\n\nBase.convert(::Type{LogScaled{L1}}, x::Gain{L2}) where {L1,L2} = Gain{L1}(_gconv(L1,L2,x))\nBase.convert(::Type{T}, y::Gain) where {T<:Real} = convert(T, uconvert(NoUnits, y))\n\nBase.convert(::Type{G}, x::Real) where {L, G <: Gain{L,:p}} =\n    G(ifelse(isrootpower(L), 0.5, 1) * tolog(L, x))\nBase.convert(::Type{G}, x::Real) where {L, G <: Gain{L,:rp}} =\n    G(ifelse(isrootpower(L), 1, 2) * tolog(L, x))\nBase.convert(::Type{<:Gain}, x::Real) = error(\"$x is not obviously a ratio of power or \",\n    \"root-power quantities; use `uconvertrp` or `uconvertp` instead.\")\n\nfunction _gconv(L1,L2,x)\n    if isrootpower(L1) == isrootpower(L2)\n        gain = tolog(L1,fromlog(L2,x.val))\n    elseif isrootpower(L1) && !isrootpower(L2)\n        gain = tolog(L1,fromlog(L2,0.5*x.val))\n    else\n        gain = tolog(L1,fromlog(L2,2*x.val))\n    end\n    return gain\nend\n\ntolog(L,S,x) = (1+isrootpower(S)) * prefactor(L()) * (logfn(L()))(x)\ntolog(L,x) = (1+isrootpower(L)) * prefactor(L()) * (logfn(L()))(x)\nfromlog(L,S,x) = unwrap(S) * expfn(L())( x / ((1+isrootpower(S))*prefactor(L())) )\nfromlog(L,x) = expfn(L())( x / ((1+isrootpower(L))*prefactor(L())) )\n\nfunction Base.show(io::IO, x::MixedUnits{T,U}) where {T,U}\n    print(io, abbr(x))\n    if x.units != NoUnits\n        print(io, \" \")\n        show(io, x.units)\n    end\nend\n\nabbr(::MixedUnits{L}) where {L <: Level} = abbr(L(reflevel(L)))\nabbr(::MixedUnits{L}) where {L <: Gain} = abbr(L(1))\n\nunit(a::MixedUnits{L,U}) where {L,U} = U()\nlogunit(a::MixedUnits{L}) where {L} = MixedUnits{L}()\nisunitless(::MixedUnits) = false\n\nBase.:*(::MixedUnits, ::MixedUnits) =\n    throw(ArgumentError(\"cannot multiply logarithmic units together.\"))\nBase.:/(::MixedUnits{T}, ::MixedUnits{S}) where {T,S} =\n    throw(ArgumentError(\"cannot divide logarithmic units except to cancel.\"))\nBase.:/(x::MixedUnits{T}, y::MixedUnits{T}) where {T} = x.units / y.units\n\nBase.:*(x::MixedUnits{T}, y::Units) where {T} = MixedUnits{T}(x.units * y)\nBase.:*(x::Units, y::MixedUnits) = y * x\nBase.:/(x::MixedUnits{T}, y::Units) where {T} = MixedUnits{T}(x.units / y)\nBase.:/(x::Units, y::MixedUnits) =\n    throw(ArgumentError(\"cannot divide logarithmic units except to cancel.\"))\n\nBase.:*(x::Real, y::MixedUnits{Level{L,S}}) where {L,S} =\n    (Level{L,S}(fromlog(L,S,x)))*y.units\nBase.:*(x::Real, y::MixedUnits{Gain{L,S}}) where {L,S} = (Gain{L,S}(x))*y.units\nBase.:*(x::MixedUnits, y::Number) = y * x\nBase.:/(x::Number, y::MixedUnits) =\n    throw(ArgumentError(\"cannot divide $x by logarithmic units.\"))\nBase.:/(x::MixedUnits, y::Number) = inv(y) * x\n\nfunction uconvert(a::Units, x::Level)\n    dimension(a) != dimension(x) && throw(DimensionError(a,x))\n    return uconvert(a, x.val)\nend\nfunction uconvert(a::Units, x::Gain)\n    dimension(a) != dimension(x) && throw(DimensionError(a,x))\n    uconvert(a, linear(x))\nend\nuconvert(a::Units, x::Quantity{<:Level}) = uconvert(a, linear(x))\nuconvert(a::Units, x::Quantity{<:Gain}) = uconvert(a, linear(x))\nfunction uconvert(a::MixedUnits{Level{L,S}}, x::Number) where {L,S}\n    dimension(a) != dimension(x) && throw(DimensionError(a,x))\n    q1 = uconvert(unit(unwrap(S))*a.units, linear(x)) / a.units\n    return Level{L,S}(q1) * a.units\nend\nfunction uconvert(a::MixedUnits{Gain{L,S}}, x::Gain) where {L,S}\n    dimension(a) != dimension(x) && throw(DimensionError(a,x))\n    return convert(Gain{L,S}, x)\nend\nfunction uconvert(a::MixedUnits{Gain{L,S}}, x::Number) where {L,S}\n    dimension(a) != dimension(x) && throw(DimensionError(a,x))\n    if S == :rp\n        return uconvertrp(a, x)\n    elseif S == :p\n        return uconvertp(a, x)\n    else\n        error(\"$x is not obviously a ratio of power or root-power quantities; \",\n            \"use `uconvertrp` or `uconvertp` instead.\")\n    end\nend\n\nfunction uconvert(a::MixedUnits{Gain{L,S}}, x::Quantity) where {L,S}\n    dimension(a) != dimension(x) && throw(DimensionError(a,x))\n    convert(Gain{L,S}, x.val) * convfact(unit(a), unit(x)) * unit(a)\nend\nfunction uconvert(a::MixedUnits{Gain{L1,S1,<:Real}}, x::Level{L2,S2}) where {L1,L2,S1,S2}\n    dimension(a) != dimension(x) && throw(DimensionError(a,x))\n    return Level{L1,S2}(x.val)\nend\n\nustrip(x::Level{L,S}) where {L<:LogInfo,S} = tolog(L,S,x.val/reflevel(x))\nustrip(x::Gain) = x.val\n\nisrootpower(y::IsRootPowerRatio{T}) where {T} = T\nisrootpower(y) = isrootpower_dim(dimension(y))\nisrootpower_dim(y) =\n    error(\"undefined behavior. Please file an issue with the code needed to reproduce.\")\n\n==(x::Gain, y::Level) = ==(y,x)\n==(x::Level, y::Gain) = false\n\nfor op in (:(==), :isequal)\n    @eval Base.$op(x::Level, y::Level) = $op(x.val, y.val)\n    @eval Base.$op(x::Gain{L,S}, y::Gain{L,S}) where {L,S} = $op(x.val, y.val)\nend\n\n# A consistent `hash` method for `Gain` is impossible with the current promotion rules\n# (https://github.com/JuliaPhysics/Unitful.jl/issues/402), therefore we don't define one.\nBase.hash(x::Level, h::UInt) = hash(x.val, h)\n\n# Addition and subtraction\nfor op in (:+, :-)\n    @eval Base.$op(x::Level{L,S}, y::Level{L,S}) where {L,S} = Level{L,S}(($op)(x.val, y.val))\n    @eval Base.$op(x::Gain{L,S}, y::Gain{L,S}) where {L,S} = Gain{L,S}(($op)(x.val, y.val))\n    @eval function Base.$op(x::Gain{L,S1}, y::Gain{L,S2}) where {L,S1,S2}\n        if S1 == :?\n            return Gain{L,S2}(($op)(x.val, y.val))\n        elseif S2 == :?\n            return Gain{L,S1}(($op)(x.val, y.val))\n        else\n            return Gain{L,:?}(($op)(x.val, y.val))\n        end\n    end\n    @eval Base.$op(x::Level{L,S}, y::Gain{L}) where {L,S} =\n        Level{L,S}(fromlog(L, S, ($op)(ustrip(x), y.val)))\nend\nBase.:+(x::Gain, y::Level) = +(y,x)\nBase.:-(x::Gain, y::Level) = throw(ArgumentError(\"cannot subtract a level from a gain.\"))\n\n# Multiplication and division\nleveltype(x::Level{L,S}) where {L,S} = Level{L,S}\nBase.:*(x::Level, y::Number) = (leveltype(x))(x.val * y)\nBase.:*(x::Level, y::Bool) = (leveltype(x))(x.val * y)    # for method ambiguity\nBase.:*(x::Level, y::AbstractQuantity) = *(x.val, y)\nBase.:*(x::Level, y::Level) = *(x.val, y.val)\nBase.:*(x::Level, y::Gain) = *(promote(x,y)...)\n\nBase.:*(x::Number, y::Level) = *(y,x)\nBase.:*(x::Bool, y::Level) = *(y,x)                       # for method ambiguity\nBase.:*(x::AbstractQuantity, y::Level) = *(y,x)           # for method ambiguity\n\ngaintype(::Gain{L,S}) where {L,S} = Gain{L,S}\nBase.:*(x::Gain, y::Number) = (gaintype(x))(x.val * y)\nBase.:*(x::Gain, y::Bool) = (gaintype(x))(x.val * y)      # for method ambiguity\nBase.:*(x::Gain, y::AbstractQuantity) = *(y,x)\nBase.:*(x::Gain, y::Level) = *(promote(x,y)...)\nBase.:*(x::Gain, y::Gain) = *(promote(x,y)...)\n\nBase.:*(x::Number, y::Gain) = *(y,x)\nBase.:*(x::Bool, y::Gain) = *(y,x)                        # for method ambiguity\nBase.:*(x::AbstractQuantity, y::Gain) =\n    isrootpower(x) ? uconvertrp(NoUnits, y) * x : uconvertp(NoUnits, y) * x\n\nfor (op1,op2) in ((:*, :+), (:/, :-))\n    @eval Base.$op1(x::Gain{L,S}, y::Gain{L,S}) where {L,S} = Gain{L,S}(($op2)(x.val, y.val))\n    @eval function Base.$op1(x::Gain{L,S1}, y::Gain{L,S2}) where {L,S1,S2}\n        if S1 == :?\n            return Gain{L,S2}(($op2)(x.val, y.val))\n        elseif S2 == :?\n            return Gain{L,S1}(($op2)(x.val, y.val))\n        else\n            return Gain{L,:?}(($op2)(x.val, y.val))\n        end\n    end\n    @eval Base.$op1(x::Level{L,S}, y::Gain{L}) where {L,S} =\n        Level{L,S}(fromlog(L, S, ($op2)(ustrip(x), y.val)))\nend\n\nBase.:*(x::Gain{L}, y::Level{L,S}) where {L,S} = Level{L,S}(fromlog(L, S, ustrip(y)+x.val))\nBase.:/(x::Gain, y::Level) = throw(ArgumentError(\"cannot divide a gain by a level.\"))\n\nBase.:/(x::Level, y::Number) = (leveltype(x))(linear(x) / y)\nBase.://(x::Level, y::Number) = (leveltype(x))(linear(x) // y)\nBase.:/(x::Level, y::AbstractQuantity) = linear(x) / y\nBase.://(x::Level, y::AbstractQuantity) = linear(x) // y\nBase.:/(x::Level, y::Level) = linear(x) / linear(y)\nBase.://(x::Level, y::Level) = linear(x) // linear(y)\nBase.://(x::Level, y::Complex) = linear(x) // y     # ambiguity resolution\n\nBase.://(x::Number, y::Level) = x // linear(y)\nBase.:/(x::AbstractQuantity, y::Level) = x / linear(y)\nBase.://(x::AbstractQuantity, y::Level) = x // linear(y)\nBase.:/(x::AbstractQuantity, y::Gain) =\n    isrootpower(x) ? x / uconvertrp(NoUnits, y) : x / uconvertp(NoUnits, y)\nBase.://(x::AbstractQuantity, y::Gain) =\n    isrootpower(x) ? x // uconvertrp(NoUnits, y) : x // uconvertp(NoUnits, y)\n\nBase.://(x::Level, y::Units) = x/y\nBase.://(x::Units, y::Level) = x//linear(y)\nBase.://(x::Gain, y::Units) = x/y\nBase.://(x::Units, y::Gain) = x//linear(y)\n\nBase.isless(x::T, y::T) where {T<:LogScaled} = isless(x.val, y.val)\n\nfunction (Base.promote_rule(::Type{Level{L1,S1,T1}}, ::Type{Level{L2,S2,T2}})\n        where {L1,L2,S1,S2,T1,T2})\n    if L1 == L2\n        if S1 == S2\n            # Use convert(promote_type(typeof(S1), typeof(S2)), S1) instead of S1?\n            return Level{L1, S1, promote_type(T1,T2)}\n        else\n            return promote_type(T1,T2)\n        end\n    else\n        return promote_type(T1,T2)\n    end\nend\n\nfunction Base.promote_rule(::Type{Quantity{T,D,U}}, ::Type{Level{L,R,S}}) where {L,R,S,T,D,U}\n    return promote_type(S, Quantity{T,D,U})\nend\nfunction Base.promote_rule(::Type{Level{L,R,S}}, ::Type{T}) where {L,R,S,T<:Real}\n    return promote_type(S,T)\nend\nfunction (Base.promote_rule(::Type{Gain{L1,S1,T1}}, ::Type{Gain{L2,S2,T2}})\n        where {L1,L2,S1,S2,T1,T2})\n    if L1 == L2\n        if S1 == :?\n            return Gain{L1,S2,promote_type(T1,T2)}\n        elseif S2 == :?\n            return Gain{L1,S1,promote_type(T1,T2)}\n        else\n            return Gain{L1,:?,promote_type(T1,T2)}\n        end\n    else\n        return promote_type(float(T1), float(T2))\n    end\nend\nfunction Base.promote_rule(::Type{G}, ::Type{N}) where {L,S,T1, G<:Gain{L,S,T1}, N<:Number}\n    if S == :?\n        error(\"no automatic promotion of $G and $N.\")\n    else\n        return Gain{L,S,promote_type(float(T1), N)}\n    end\nend\nBase.promote_rule(A::Type{G}, B::Type{L}) where {G<:Gain, L2, L<:Level{L2}} = LogScaled{L2}\n\nfunction Base.show(io::IO, x::Gain)\n    print(io, x.val, \" \", abbr(x))\n    nothing\nend\nfunction Base.show(io::IO, x::Level)\n    print(io, ustrip(x), \" \", abbr(x))\n    nothing\nend\n\nfunction Base.alignment(io::IO, x::Gain)\n    length = printed_length(io, x)\n    left, _ = Base.alignment(io, x.val)\n    return left, length - left\nend\nfunction Base.alignment(io::IO, x::Level)\n    length = printed_length(io, x)\n    left, _ = Base.alignment(io, ustrip(x))\n    return left, length - left\nend\n\nBracketStyle(::Type{<:Union{Level,Gain}}) = SquareBrackets()\n\n\"\"\"\n    uconvertp(u::Units, x)\n    uconvertp(u::MixedUnits, x)\nGenerically, this is the same as [`Unitful.uconvert`](@ref). In cases where unit conversion\nwould be ambiguous without further information (e.g. `uconvert(dB, 10)`), `uconvertp`\npresumes ratios are of power quantities.\n\nIt is important to note that careless use of this function can lead to erroneous calculations.\nConsider `Quantity{<:Gain}` types: it is tempting to use this to transform `-20dB/m` into\n`0.1/m`, however this means something fundamentally different than `-20dB/m`. Consider what\nhappens when you try to compute exponential attenuation by multiplying `0.1/m` by a length.\n\nExamples:\n```jldoctest\njulia> using Unitful\n\njulia> uconvertp(u\"dB\", 10)\n10.0 dB\n\njulia> uconvertp(NoUnits, 20u\"dB\")\n100.0\n```\n\"\"\"\nfunction uconvertp end\nuconvertp(u, x) = uconvert(u, x)    # fallback\nuconvertp(::Units{()}, x::Gain{L}) where {L} =\n    fromlog(L, ifelse(isrootpower(L), 2, 1)*x.val)\nuconvertp(u::T, x::Real) where {L, G <: Gain{L}, T <: MixedUnits{G, <:Units{()}}} =\n    convert(Gain{L,:p}, x)\n# function uconvertp(a::MixedUnits{Gain{L}}, x::Number) where {L}\n#     dimension(a) != dimension(x) && throw(DimensionError(a,x))\n#\n# end\n\n\"\"\"\n    uconvertrp(u::Units, x)\n    uconvertrp(u::MixedUnits, x)\nIn most cases, this is the same as [`Unitful.uconvert`](@ref). In cases where unit conversion\nwould be ambiguous without further information (e.g. `uconvert(dB, 10)`), `uconvertrp`\npresumes ratios are of root-power quantities.\n\nIt is important to note that careless use of this function can lead to erroneous calculations.\nConsider `Quantity{<:Gain}` types: it is tempting to use this to transform `-20dB/m` into\n`0.01/m`, however this means something fundamentally different than `-20dB/m`. Consider what\nhappens when you try to compute exponential attenuation by multiplying `0.01/m` by a length.\n\"\"\"\nfunction uconvertrp end\nuconvertrp(u, x) = uconvert(u, x)\nuconvertrp(::Units{()}, x::Gain{L}) where {L} =\n    fromlog(L, ifelse(isrootpower(L), 1.0, 0.5)*x.val)\nuconvertrp(u::T, x::Real) where {L, G <: Gain{L}, T <: MixedUnits{G, <:Units{()}}} =\n    convert(Gain{L,:rp}, x)\n\n\"\"\"\n    linear(x::Quantity)\n    linear(x::Level)\n    linear(x::Number) = x\nReturns a quantity equivalent to `x` but without any logarithmic scales.\n\nIt is important to note that this operation will error for `Quantity{<:Gain}` types. This\nis for two reasons:\n\n- `20dB` could be interpreted as either a power or root-power ratio.\n- Even if `-20dB/m` were interpreted as, say, `0.01/m`, this means something fundamentally\n  different than `-20dB/m`. `0.01/m` cannot be used to calculate exponential attenuation.\n\"\"\"\nlinear(x::Quantity{<:Level}) = (x.val.val)*unit(x)\nlinear(x::Quantity{<:Gain{L,:?}}) where {L} = error(\"ambiguous how to linearize. Cannot determine \",\n    \"whether to use `uconvertrp` or `uconvertp` from the type of $x: `$(typeof(x))`.\")\nlinear(x::Quantity{<:Gain{L,:rp}}) where {L} = uconvertrp(NoUnits, x.val)*unit(x)\nlinear(x::Quantity{<:Gain{L,:p}}) where {L} = uconvertp(NoUnits, x.val)*unit(x)\nlinear(x::Level) = x.val\nlinear(x::Gain{L,:rp}) where {L} = uconvertrp(NoUnits, x)\nlinear(x::Gain{L,:p}) where {L} = uconvertp(NoUnits, x)\nlinear(x::Gain{L,:?}) where {L} = error(\"ambiguous how to linearize. Cannot determine \",\n    \"whether to use `uconvertrp` or `uconvertp` from the type of $x: `$(typeof(x))`.\")\nlinear(x::Number) = x\n\n\"\"\"\n    logfn(x::LogInfo)\nReturns the appropriate logarithm function to use in calculations involving the\nlogarithmic unit / quantity. For example, decibel-based units yield `log10`,\nNeper-based yield `ln`, and so on. Returns `x->log(base, x)` as a fallback.\n\"\"\"\nfunction logfn end\nlogfn(x::LogInfo{N,10}) where {N} = log10\nlogfn(x::LogInfo{N,2})  where {N} = log2\nlogfn(x::LogInfo{N,ℯ})  where {N} = log\nlogfn(x::LogInfo{N,B})  where {N,B} = x->log(B,x)\n\n\"\"\"\n    expfn(x::LogInfo)\nReturns the appropriate exponential function to use in calculations involving the\nlogarithmic unit / quantity. For example, decibel-based units yield `exp10`,\nNeper-based yield `exp`, and so on. Returns `x->(base)^x` as a fallback.\n\"\"\"\nfunction expfn end\nexpfn(x::LogInfo{N,10}) where {N} = exp10\nexpfn(x::LogInfo{N,2})  where {N} = exp2\nexpfn(x::LogInfo{N,ℯ})  where {N} = exp\nexpfn(x::LogInfo{N,B})  where {N,B} = x->B^x\n\nBase.rtoldefault(::Type{Level{L,S,T}}) where {L,S,T} =\n    Base.rtoldefault(typeof(tolog(L,S,oneunit(T)/unwrap(S))))\nBase.rtoldefault(::Type{Gain{L,S,T}}) where {L,S,T} = Base.rtoldefault(T)\n\nBase.isapprox(x::Level, y::Level; kwargs...) = isapprox(promote(x,y)...; kwargs...)\nBase.isapprox(x::T, y::T; kwargs...) where {T <: Level} = _isapprox(x, y; kwargs...)\n_isapprox(x::Level{L,S,T}, y::Level{L,S,T}; atol = Level{L,S}(reflevel(x)), kwargs...) where {L,S,T} =\n    isapprox(ustrip(x), ustrip(y); atol = ustrip(convert(Level{L,S}, atol)),\n        kwargs...)\n\nBase.isapprox(x::Gain, y::Gain; kwargs...) = isapprox(promote(x,y)...; kwargs...)\nBase.isapprox(x::T, y::T; kwargs...) where {T <: Gain} = _isapprox(x, y; kwargs...)\n_isapprox(x::Gain{L,S,T}, y::Gain{L,S,T}; atol = Gain{L}(oneunit(T)), kwargs...) where {L,S,T} =  #TODO\n    isapprox(ustrip(x), ustrip(y); atol = ustrip(convert(Gain{L,S,T}, atol)), kwargs...)\n\n*(A::MixedUnits, B::AbstractArray) = broadcast(*, A, B)\n*(A::AbstractArray, B::MixedUnits) = broadcast(*, A, B)\n\nBase.broadcastable(x::MixedUnits) = Ref(x)\n"
  },
  {
    "path": "src/pkgdefaults.jl",
    "content": "# Default dimensions and their abbreviations.\n# The dimension symbols are generated by tab completion: \\bfL is 𝐋, etc.\n# At the expense of easy typing, this gives a visual cue to distinguish\n# dimensions from units, and also helps prevent common namespace collisions.\n\"    Unitful.𝐋\n\\nA dimension representing length.\"\n@dimension 𝐋 \"𝐋\" Length      true\n\"    Unitful.𝐌\n\\nA dimension representing mass.\"\n@dimension 𝐌 \"𝐌\" Mass       true\n\"    Unitful.𝐓\n\\nA dimension representing time.\"\n@dimension 𝐓 \"𝐓\" Time        true\n\"    Unitful.𝐈\n\\nA dimension representing electric current.\"\n@dimension 𝐈 \"𝐈\" Current      true\n\"    Unitful.𝚯\n\\nA dimension representing thermodynamic temperature.\"\n@dimension 𝚯 \"𝚯\" Temperature true   # This one is \\bfTheta\n\"    Unitful.𝐉\n\\nA dimension representing luminous intensity.\"\n@dimension 𝐉 \"𝐉\" Luminosity   true\n\"    Unitful.𝐍\n\\nA dimension representing amount of substance.\"\n@dimension 𝐍 \"𝐍\" Amount      true\nconst RelativeScaleTemperature = Quantity{T, 𝚯, <:AffineUnits} where T\nconst AbsoluteScaleTemperature = Quantity{T, 𝚯, <:ScalarUnits} where T\n\n# Define derived dimensions.\n@derived_dimension Area                     𝐋^2 true\n@derived_dimension Volume                   𝐋^3 true\n@derived_dimension Density                  𝐌/𝐋^3 true\n@derived_dimension Frequency                inv(𝐓) true\n@derived_dimension Velocity                 𝐋/𝐓 true\n@derived_dimension Acceleration             𝐋/𝐓^2 true\n@derived_dimension Force                    𝐌*𝐋/𝐓^2 true\n@derived_dimension Pressure                 𝐌*𝐋^-1*𝐓^-2 true\n@derived_dimension Energy                   𝐌*𝐋^2/𝐓^2 true\n@derived_dimension Momentum                 𝐌*𝐋/𝐓 true\n@derived_dimension Power                    𝐋^2*𝐌*𝐓^-3 true\n@derived_dimension Charge                   𝐈*𝐓 true\n@derived_dimension Voltage                  𝐈^-1*𝐋^2*𝐌*𝐓^-3 true\n@derived_dimension ElectricalResistance     𝐈^-2*𝐋^2*𝐌*𝐓^-3 true\n@derived_dimension ElectricalResistivity    𝐈^-2*𝐋^3*𝐌*𝐓^-3 true\n@derived_dimension ElectricalConductance    𝐈^2*𝐋^-2*𝐌^-1*𝐓^3 true\n@derived_dimension ElectricalConductivity   𝐈^2*𝐋^-3*𝐌^-1*𝐓^3 true\n@derived_dimension Capacitance              𝐈^2*𝐋^-2*𝐌^-1*𝐓^4 true\n@derived_dimension Inductance               𝐈^-2*𝐋^2*𝐌*𝐓^-2 true\n@derived_dimension MagneticFlux             𝐈^-1*𝐋^2*𝐌*𝐓^-2 true\n@derived_dimension DField                   𝐈*𝐓/𝐋^2 true\n@derived_dimension EField                   𝐋*𝐌*𝐓^-3*𝐈^-1 true\n@derived_dimension HField                   𝐈/𝐋 true\n@derived_dimension BField                   𝐈^-1*𝐌*𝐓^-2 true\n@derived_dimension Action                   𝐋^2*𝐌*𝐓^-1 true\n@derived_dimension DynamicViscosity         𝐌*𝐋^-1*𝐓^-1 true\n@derived_dimension KinematicViscosity       𝐋^2*𝐓^-1 true\n@derived_dimension Wavenumber               inv(𝐋) true\n@derived_dimension ElectricDipoleMoment     𝐋*𝐓*𝐈 true\n@derived_dimension ElectricQuadrupoleMoment 𝐋^2*𝐓*𝐈 true\n@derived_dimension MagneticDipoleMoment     𝐋^2*𝐈 true\n@derived_dimension Molarity                 𝐍/𝐋^3 true\n@derived_dimension Molality                 𝐍/𝐌 true\n@derived_dimension MolarMass                𝐌/𝐍 true\n@derived_dimension MassFlow                 𝐌/𝐓 true\n@derived_dimension MolarFlow                𝐍/𝐓 true\n@derived_dimension VolumeFlow               𝐋^3/𝐓 true\n\n# Define base units. This is not to imply g is the base SI unit instead of kg.\n# See the documentation for further details.\n# #key:   Symbol  Display  Name      Dimension   Prefixes?\n\"    Unitful.m\n\\nThe meter, the SI base unit of length.\n\\nDimension: [`Unitful.𝐋`](@ref).\"\n@refunit  m       \"m\"      Meter     𝐋           true true\n\"    Unitful.s\n\\nThe second, the SI base unit of time.\n\\nDimension: [`Unitful.𝐓`](@ref).\"\n@refunit  s       \"s\"      Second    𝐓           true true\n\"    Unitful.A\n\\nThe ampere, the SI base unit of electric current.\n\\nDimension: [`Unitful.𝐈`](@ref).\"\n@refunit  A       \"A\"      Ampere    𝐈            true true\n\"    Unitful.K\n\\nThe kelvin, the SI base unit of thermodynamic temperature.\n\\nDimension: [`Unitful.𝚯`](@ref).\"\n@refunit  K       \"K\"      Kelvin    𝚯           true true\n\"    Unitful.cd\n\\nThe candela, the SI base unit of luminous intensity.\n\\nDimension: [`Unitful.𝐉`](@ref).\"\n@refunit  cd      \"cd\"     Candela   𝐉            true true\n# the docs for all gram-based units are defined later, to ensure kg is the base unit.\n@refunit  g       \"g\"      Gram      𝐌           true\n\"    Unitful.mol\n\\nThe mole, the SI base unit for amount of substance.\n\\nDimension: [`Unitful.𝐍`](@ref).\"\n@refunit  mol     \"mol\"    Mole      𝐍           true true\n\n# Angles and solid angles\n\"    Unitful.sr\n\\nThe steradian, a unit of spherical angle. There are 4π sr in a sphere.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit sr      \"sr\"      Steradian   1                       true true\n\"    Unitful.rad\n\\nThe radian, a unit of angle. There are 2π rad in a circle.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit rad     \"rad\"     Radian      1                       true true\n\"    Unitful.°\n    Unitful.deg\n\\nThe degree, a unit of angle. There are 360° in a circle.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n((@unit °       \"°\"       Degree      pi/180                  false), const deg = °)\n# For numerical accuracy, specific to the degree\nimport Base: sind, cosd, sincosd, tand, secd, cscd, cotd\nfor (_x,_y) in ((:sin,:sind), (:cos,:cosd), (:sincos,:sincosd), (:tan,:tand),\n        (:sec,:secd), (:csc,:cscd), (:cot,:cotd))\n    @eval ($_x)(x::Quantity{T, NoDims, typeof(°)}) where {T} = ($_y)(ustrip(x))\n    @eval ($_y)(x::Quantity{T, NoDims, typeof(°)}) where {T} = ($_y)(ustrip(x))\nend\nfor f in (:cos, :sin, :tan, :sincos, :cis)\n    f_fast = fast_op[f]\n    # Use deg2rad because uncnvert only has Float64 precision\n    @eval $f_fast(x::Quantity{T, NoDims, typeof(°)}) where {T} = $f_fast(deg2rad(x.val))\nend\n\n# conversion between degrees and radians\nimport Base: deg2rad, rad2deg\ndeg2rad(d::Quantity{T, NoDims, typeof(°)}) where {T} = deg2rad(ustrip(°, d)) * rad\nrad2deg(r::Quantity{T, NoDims, typeof(rad)}) where {T} = rad2deg(ustrip(rad, r)) * °\n\n# SI and related units\n\"    Unitful.Hz\n\\nThe hertz, an SI unit of frequency, defined as 1 s^-1.\n\\nDimension: 𝐓^-1.\n\\nSee also: [`Unitful.s`](@ref).\"\n@unit Hz              \"Hz\"   Hertz           1/s                true true\n\"    Unitful.N\n\\nThe newton, an SI unit of force, defined as 1 kg × m / s^2.\n\\nDimension: 𝐋 𝐌 𝐓^-2.\n\\nSee also: [`Unitful.kg`](@ref), [`Unitful.m`](@ref), [`Unitful.s`](@ref).\"\n@unit N               \"N\"    Newton          1kg*m/s^2          true true\n\"    Unitful.Pa\n\\nThe pascal, an SI unit of pressure, defined as 1 N / m^2.\n\\nDimension: 𝐌 𝐋^-1 𝐓^-2.\n\\nSee also: [`Unitful.N`](@ref), [`Unitful.m`](@ref).\"\n@unit Pa              \"Pa\"   Pascal          1N/m^2             true true\n\"    Unitful.J\n\\nThe joule, an SI unit of energy, defined as 1 N × m.\n\\nDimension: 𝐋^2 𝐌 𝐓^-2.\n\\nSee also: [`Unitful.N`](@ref), [`Unitful.m`](@ref).\"\n@unit J               \"J\"    Joule           1N*m               true true\n\"    Unitful.W\n\\nThe watt, an SI unit of power, defined as 1 J / s.\n\\nDimension: 𝐋^2 𝐌 𝐓^-3.\n\\nSee also: [`Unitful.J`](@ref), [`Unitful.s`](@ref).\"\n@unit W               \"W\"    Watt            1J/s               true true\n\"    Unitful.C\n\\nThe coulomb, an SI unit of electric charge, defined as 1 A × s.\n\\nDimension: 𝐈 𝐓.\n\\nSee also: [`Unitful.A`](@ref), [`Unitful.s`](@ref).\"\n@unit C               \"C\"    Coulomb         1A*s               true true\n\"    Unitful.V\n\\nThe volt, an SI unit of electric potential, defined as 1 W / A.\n\\nDimension: 𝐋^2 𝐌 𝐈^-1 𝐓^-3.\n\\nSee also: [`Unitful.W`](@ref), [`Unitful.A`](@ref)\"\n@unit V               \"V\"    Volt            1W/A               true true\n\"    Unitful.Ω\n\\nThe ohm, an SI unit of electrical resistance, defined as 1 V / A.\n\\nDimension: 𝐋^2 𝐌 𝐈^-2 𝐓^-3.\n\\nSee also: [`Unitful.V`](@ref), [`Unitful.A`](@ref).\"\n@unit Ω               \"Ω\"    Ohm             1V/A               true true\n\"    Unitful.S\n\\nThe siemens, an SI unit of electrical conductance, defined as 1 Ω^-1.\n\\nDimension: 𝐈^2 𝐓^3 𝐋^-2 𝐌^-1.\n\\nSee also: [`Unitful.Ω`](@ref)\"\n@unit S               \"S\"    Siemens         1/Ω                true true\n\"    Unitful.F\n\\nThe farad, an SI unit of electrical capacitance, defined as 1 s^4 × A^2 / (kg × m^2).\n\\nDimension: 𝐈^2 𝐓^4 𝐋^-2 𝐌^-1.\n\\nSee also: [`Unitful.s`](@ref), [`Unitful.A`](@ref), [`Unitful.kg`](@ref), [`Unitful.m`](@ref).\"\n@unit F               \"F\"    Farad           1s^4*A^2/(kg*m^2)  true true\n\"    Unitful.H\n\\nThe henry, an SI unit of electrical inductance, defined as 1 J / A^2.\n\\nDimension: 𝐋^2 𝐌 𝐈^-2 𝐓^-2.\n\\nSee also: [`Unitful.J`](@ref), [`Unitful.A`](@ref).\"\n@unit H               \"H\"    Henry           1J/(A^2)           true true\n\"    Unitful.T\n\\nThe tesla, an SI unit of magnetic B-field strength, defined as 1 kg / (A × s^2).\n\\nDimension: 𝐌 𝐈^-1 𝐓^-2.\n\\nSee also: [`Unitful.kg`](@ref), [`Unitful.A`](@ref), [`Unitful.s`](@ref).\"\n@unit T               \"T\"    Tesla           1kg/(A*s^2)        true true\n\"    Unitful.Wb\n\\nThe weber, an SI unit of magnetic flux, defined as 1 kg × m^2 / (A × s^2).\n\\nDimension: 𝐋^2 𝐌 𝐈^-1 𝐓^-2.\n\\nSee also: [`Unitful.kg`](@ref), [`Unitful.m`](@ref), [`Unitful.A`](@ref), [`Unitful.s`](@ref).\"\n@unit Wb              \"Wb\"   Weber           1kg*m^2/(A*s^2)    true true\n\"    Unitful.lm\n\\nThe lumen, an SI unit of luminous flux, defined as 1 cd × sr.\n\\nDimension: [`Unitful.𝐉`](@ref).\n\\nSee also: [`Unitful.cd`](@ref), [`Unitful.sr`](@ref).\"\n@unit lm              \"lm\"   Lumen           1cd*sr             true true\n\"    Unitful.lx\n\\nThe lux, an SI unit of illuminance, defined as 1 lm / m^2.\n\\nDimension: 𝐉 𝐋^-2.\n\\nSee also: [`Unitful.lm`](@ref), [`Unitful.m`](@ref).\"\n@unit lx              \"lx\"   Lux             1lm/m^2            true true\n\"    Unitful.Bq\n\\nThe becquerel, an SI unit of radioactivity, defined as 1 nuclear decay per s.\n\\nDimension: 𝐓^-1.\n\\nSee also: [`Unitful.s`](@ref).\"\n@unit Bq              \"Bq\"   Becquerel       1/s                true true\n\"    Unitful.Gy\n\\nThe gray, an SI unit of ionizing radiation dose, defined as the absorption of 1 J per kg of matter.\n\\nDimension: 𝐋^2 𝐓^-2.\n\\nSee also: [`Unitful.lm`](@ref), [`Unitful.m`](@ref).\"\n@unit Gy              \"Gy\"   Gray            1J/kg              true true\n\"    Unitful.Sv\n\\nThe sievert, an SI unit of the biological effect of an ionizing radiation dose.\nDefined as the health effect of 1 Gy of radiation, scaled by a quality factor.\n\\nDimension: 𝐋^2 𝐓^-2.\n\\nSee also: [`Unitful.Gy`](@ref).\"\n@unit Sv              \"Sv\"   Sievert         1J/kg              true true\n\"    Unitful.kat\n\\nThe katal, an SI unit of catalytic activity, defined as 1 mol of catalyzed\nsubstrate per s.\n\\nDimension: 𝐍 𝐓^-1.\n\\nSee also: [`Unitful.mol`](@ref), [`Unitful.s`](@ref).\"\n@unit kat             \"kat\"  Katal           1mol/s             true true\n\"    Unitful.percent\n\\nPercent, a unit meaning parts per hundred. Printed as \\\"%\\\".\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit percent         \"%\"    Percent         1//100             false\n\"    Unitful.permille\n\\nPermille, a unit meaning parts per thousand. Printed as \\\"‰\\\".\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit permille        \"‰\"    Permille        1//1000            false\n\"    Unitful.pertenthousand\n\\nPermyriad, a unit meaning parts per ten thousand. Printed as \\\"‱\\\".\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit pertenthousand  \"‱\"    Pertenthousand  1//10000           false\n\"    Unitful.pcm\n\\nPercentmille, a unit meaning parts per hundred thousand.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit pcm             \"pcm\"  Percentmille    1//100000          false\n\"    Unitful.ppm\n\\nPermillion, a unit meaning parts per million.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit ppm             \"ppm\"  Permillion      1//1000000         false\n\"    Unitful.ppb\n\\nPerbillion, a unit meaning parts per billion (in the short-scale sense), i.e., 10^-9.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit ppb             \"ppb\"  Perbillion      1//1000000000      false\n\"    Unitful.ppt\n\\nPertrillion, a unit meaning parts per trillion (in the short-scale sense), i.e., 10^-12.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit ppt             \"ppt\"  Pertrillion     1//1000000000000   false\n\"    Unitful.ppq\n\\nPerquadrillion, a unit meaning parts per quadrillion (in the short-scale sense), i.e., 10^-15.\n\\nDimension: [`Unitful.NoDims`](@ref).\"\n@unit ppq             \"ppq\"  Perquadrillion  1//1000000000000000  false\n\n# Temperature\n\"    Unitful.°C\n    Unitful.degC\n\\nThe degree Celsius, an SI unit of temperature, defined such that 0 °C = 273.15 K.\n\\nDimension: [`Unitful.𝚯`](@ref).\n\\nSee also: [`Unitful.K`](@ref).\"\n((@affineunit °C \"°C\"     (27315//100)K), const degC = °C)\n\n# Common units of time\n\"    Unitful.minute\n\\nThe minute, a unit of time defined as 60 s. The full name `minute` is used instead of the symbol `min`\nto avoid confusion with the Julia function `min`.\n\\nDimension: [`Unitful.𝐓`](@ref).\n\\nSee Also: [`Unitful.s`](@ref).\"\n@unit minute \"minute\"   Minute                60s           false\n\"    Unitful.hr\n\\nThe hour, a unit of time defined as 60 minutes.\n\\nDimension: [`Unitful.𝐓`](@ref).\n\\nSee Also: [`Unitful.minute`](@ref).\"\n@unit hr     \"hr\"       Hour                  3600s         false\n\"    Unitful.d\n\\nThe day, a unit of time defined as 24 hr.\n\\nDimension: [`Unitful.𝐓`](@ref).\n\\nSee Also: [`Unitful.hr`](@ref).\"\n@unit d      \"d\"        Day                   86400s        false\n\"    Unitful.wk\n\\nThe week, a unit of time, defined as 7 d.\n\\nDimension: [`Unitful.𝐓`](@ref).\n\\nSee Also: [`Unitful.d`](@ref).\"\n@unit wk     \"wk\"       Week                  604800s       false\n\"    Unitful.yr\n\\nThe year, a unit of time, defined as 365.25 d.\n\\nDimension: [`Unitful.𝐓`](@ref).\n\\nSee Also: [`Unitful.hr`](@ref).\"\n@unit yr     \"yr\"       Year                  31557600s     true true\n\"    Unitful.rps\n\\nRevolutions per second, a unit of rotational speed, defined as 2π rad / s.\n\\nDimension: 𝐓^-1.\n\\nSee Also: [`Unitful.rad`](@ref), [`Unitful.s`](@ref).\"\n@unit rps    \"rps\"      RevolutionsPerSecond  2π*rad/s      false\n\"    Unitful.rpm\n\\nRevolutions per minute, a unit of rotational speed, defined as 2π rad / minute.\n\\nDimension: 𝐓^-1.\n\\nSee Also: [`Unitful.minute`](@ref), [`Unitful.rad`](@ref).\"\n@unit rpm    \"rpm\"      RevolutionsPerMinute  2π*rad/minute false\n\n# Area\n# The hectare is used more frequently than any other power-of-ten of an are.\n\"    Unitful.a\n\\nThe are, a metric unit of area, defined as 100 m^2.\n\\nDimension: 𝐋^2.\n\\nSee Also: [`Unitful.m`](@ref).\"\n@unit a      \"a\"        Are         100m^2                  false\n\"    Unitful.ha\n\\nThe hectare, a metric unit of area, defined as 100 a.\n\\nDimension: 𝐋^2.\n\\nSee Also: [`Unitful.a`](@ref).\"\nconst ha = Unitful.FreeUnits{(Unitful.Unit{:Are, 𝐋^2}(2, 1//1),), 𝐋^2}()\n\"    Unitful.b\n\\nThe barn, a metric unit of area, defined as 100 fm^2.\n\\nDimension: 𝐋^2.\n\\nSee Also: [`Unitful.fm`](@ref).\"\n@unit b      \"b\"        Barn        100fm^2                 true true\n\n# Volume\n# `l` is also an acceptable symbol for liters\n\"    Unitful.L\n    Unitful.l\n\\nThe liter, a metric unit of volume, defined as 1000 cm^3.\n\\nDimension: 𝐋^3.\n\\nSee Also: [`Unitful.cm`](@ref).\"\n((@unit L    \"L\"        Liter       m^3//1000               true), const l = L)\nfor (k,v) in prefixdict\n    if k != 0\n        sym_L = Symbol(v,:L)\n        sym_l = Symbol(v,:l)\n        docstring = \"\"\"\n                        Unitful.$sym_L\n                        Unitful.$sym_l\n\n                    A prefixed unit, equal to 10^$k L.\n\n                    Dimension: 𝐋^3.\n\n                    See also: [`Unitful.L`](@ref).\n                    \"\"\"\n        run = quote @doc $docstring ((const $sym_l = $sym_L), $sym_L) end\n        eval(run)\n    end\nend\n\n# Molarity\n\"    Unitful.M\n\\nA unit for measuring molar concentration, equal to 1 mol/L.\n\\nDimension: 𝐍 𝐋^-3.\n\\nSee Also: [`Unitful.L`](@ref), [`Unitful.mol`](@ref).\"\n@unit M      \"M\"        Molar       1mol/L                  true true\n\n# Energy\n\"    Unitful.q\n\\nA quantity equal to the elementary charge, the charge of a single electron,\nwith a value of exactly 1.602,176,634 × 10^-19 C. The letter `q` is used instead of `e` to avoid\nconfusion with Euler's number.\n\\nDimension: 𝐈 𝐓.\n\\nSee Also: [`Unitful.C`](@ref).\"\nconst q = 1.602_176_634e-19*C        # CODATA 2018; `e` means 2.718...\n\"    Unitful.eV\n\\nThe electron-volt, a unit of energy, defined as q*V.\n\\nDimension: 𝐋^2 𝐌 𝐓^-2.\n\\nSee also: [`Unitful.q`](@ref), [`Unitful.V`](@ref).\"\n@unit eV     \"eV\"       eV          q*V                     true true\n\n# For convenience\n\"    Unitful.Hz2π\n\\nA unit for convenience in angular frequency, equal to 2π Hz.\n\\nDimension: 𝐓^-1.\n\\nSee also: [`Unitful.Hz`](@ref).\"\n@unit Hz2π   \"Hz2π\"     AngHertz    2π/s                    true true\n\"    Unitful.bar\n\\nThe bar, a metric unit of pressure, defined as 100 kPa.\n\\nDimension: 𝐌 𝐋^-1 𝐓^-2.\n\\nSee also: [`Unitful.kPa`](@ref).\"\n@unit bar    \"bar\"      Bar         100000Pa                true true\n\"    Unitful.atm\n\\nThe standard atmosphere, a unit of pressure, defined as 101,325 Pa.\n\\nDimension: 𝐌 𝐋^-1 𝐓^-2.\n\\nSee also: [`Unitful.Pa`](@ref).\"\n@unit atm    \"atm\"      Atmosphere  101325Pa                true true\n\"    Unitful.Torr\n\\nThe torr, a unit of pressure, defined as 1/760 atm.\n\\nDimension: 𝐌 𝐋^-1 𝐓^-2.\n\\nSee also: [`Unitful.atm`](@ref).\"\n@unit Torr   \"Torr\"     Torr        101325Pa//760           true true\n\n# Constants (2018 CODATA values)        (uncertainties in final digits)\n\"    Unitful.c0\n\\nA quantity representing the speed of light in a vacuum, defined as exactly\n2.997,924,58 × 10^8 m/s.\n\\n`Unitful.c0` is a quantity (with units `m/s`) whereas [`Unitful.c`](@ref) is a unit equal to `c0`.\n\\nDimension: 𝐋 𝐓^-1.\n\\nSee also: [`Unitful.m`](@ref), [`Unitful.s`](@ref).\"\nconst c0 = 299_792_458*m/s              # exact\n\"    Unitful.c\n\\nThe speed of light in a vacuum, a unit of speed, defined as exactly\n2.997,924,58 × 10^8 m/s.\n\\n[`Unitful.c0`](@ref) is a quantity (with units `m/s`) whereas `Unitful.c` is a unit equal to `c0`.\n\\nDimension: 𝐋 𝐓^-1.\n\\nSee also: [`Unitful.m`](@ref), [`Unitful.s`](@ref).\"\n@unit c      \"c\"        SpeedOfLight 1c0                    false\n\"    Unitful.μ0\n\\nA quantity representing the vacuum permeability constant, defined as 4π × 10^-7 H / m.\n\\nDimension: 𝐋 𝐌 𝐈^-2 𝐓^-2.\n\\nSee also: [`Unitful.H`](@ref), [`Unitful.m`](@ref).\"\nconst μ0 = 4π*(1//10)^7*H/m         # exact (but gets promoted to Float64...), magnetic constant\n\"    Unitful.ε0\n    Unitful.ϵ0\n\\nA quantity representing the vacuum permittivity constant, defined as 1 / (μ0 × c^2).\n\\nDimension: 𝐈^2 𝐓^4 𝐋^-3 𝐌^-1.\n\\nSee also: [`Unitful.μ0`](@ref), [`Unitful.c`](@ref).\"\n((const ε0 = 1/(μ0*c^2)), const ϵ0 = ε0) # exact, electric constant; changes here may affect test of issue 79.\n\"    Unitful.Z0\n\\nA quantity representing the impedance of free space, a constant defined as μ0 × c.\n\\nDimension: 𝐋^2 𝐌 𝐈^-2 𝐓^-3.\n\\nSee also: [`Unitful.μ0`](@ref), [`Unitful.c`](@ref).\"\nconst Z0 = μ0*c                     # exact, impedance of free space\n\"    Unitful.G\n\\nA quantity representing the universal gravitational constant, equal to\n6.674,30 × 10^-11 m^3 / (kg × s^2) (the CODATA 2018 recommended value).\n\\nDimension: 𝐋^3 𝐌^-1 𝐓^-2.\n\\nSee also: [`Unitful.m`](@ref), [`Unitful.kg`](@ref), [`Unitful.s`](@ref).\"\nconst G  = 6.674_30e-11*m^3/kg/s^2  # (15) gravitational constant\n\"    Unitful.gn\n\\nA quantity representing the nominal acceleration due to gravity in a vacuum\nnear the surface of the earth, defined by standard to be exactly 9.806,65 m / s^2.\n\\n`Unitful.gn` is a quantity (with units `m/s^2`) whereas [`Unitful.ge`](@ref) is a unit equal to `gn`.\n\\nDimension: 𝐋 𝐓^-2.\n\\nSee also: [`Unitful.m`](@ref), [`Unitful.s`](@ref).\"\nconst gn = 9.80665*m/s^2            # exact, standard acceleration of gravity\n\"    Unitful.h\n\\nA quantity representing Planck's constant, defined as exactly\n6.626,070,15 × 10^-34 J × s.\n\\nDimension: 𝐋^2 𝐌 𝐓^-1.\n\\nSee also: [`Unitful.J`](@ref), [`Unitful.s`](@ref).\"\nconst h  = 6.626_070_15e-34*J*s     # exact, Planck constant\n\"    Unitful.ħ\n\\nA quantity representing the reduced Planck constant, defined as h / 2π.\n\\nDimension: 𝐋^2 𝐌 𝐓^-1.\n\\nSee also: [`Unitful.h`](@ref).\"\nconst ħ  = h/2π                     # hbar\n\"    Unitful.Φ0\n\\nA quantity representing the superconducting magnetic flux quantum, defined as\nh / (2 × q).\n\\nDimension: 𝐋^2 𝐌 𝐈^-1 𝐓^-2.\n\\nSee also: [`Unitful.h`](@ref), [`Unitful.q`](@ref).\"\nconst Φ0 = h/(2q)                   # Superconducting magnetic flux quantum\n\"    Unitful.me\n\\nA quantity representing the rest mass of an electron, equal to 9.109,383,7015\n× 10^-31 kg (the CODATA 2018 recommended value).\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee also: [`Unitful.kg`](@ref).\"\nconst me = 9.109_383_7015e-31*kg    # (28) electron rest mass\n\"    Unitful.mn\n\\nA quantity representing the rest mass of a neutron, equal to 1.674,927,498,04\n× 10^-27 kg (the CODATA 2018 recommended value).\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee also: [`Unitful.kg`](@ref).\"\nconst mn = 1.674_927_498_04e-27*kg  # (95) neutron rest mass\n\"    Unitful.mp\n\\nA quantity representing the rest mass of a proton, equal to 1.672,621,923,69\n× 10^-27 kg (the CODATA 2018 recommended value).\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee also: [`Unitful.kg`](@ref).\"\nconst mp = 1.672_621_923_69e-27*kg  # (51) proton rest mass\n\"    Unitful.μB\n\\nA quantity representing the Bohr magneton, equal to q × ħ / (2 × me).\n\\nDimension: 𝐈 𝐋^2.\n\\nSee also: [`Unitful.q`](@ref), [`Unitful.ħ`](@ref), [`Unitful.me`](@ref).\"\nconst μB = q*ħ/(2*me)               # Bohr magneton\n\"    Unitful.Na\n\\nA quantity representing Avogadro's constant, defined as exactly\n6.022,140,76 × 10^23 / mol.\n\\nDimension: 𝐍^-1.\n\\nSee also: [`Unitful.mol`](@ref).\"\nconst Na = 6.022_140_76e23/mol      # exact, Avogadro constant\n\"    Unitful.k\n\\nA quantity representing the Boltzmann constant, defined as exactly\n1.380,649 × 10^-23 J / K.\n\\nDimension: 𝐋^2 𝐌 𝚯^-1 𝐓^-2.\n\\nSee also: [`Unitful.J`](@ref), [`Unitful.K`](@ref).\"\nconst k  = 1.380_649e-23*(J/K)      # exact, Boltzmann constant\n\"    Unitful.R\n\\nA quantity representing the molar gas constant, defined as\nNa × k.\n\\nDimension: 𝐋^2 𝐌 𝐍^-1 𝚯^-1 𝐓^-2.\n\\nSee also: [`Unitful.Na`](@ref), [`Unitful.k`](@ref).\"\nconst R  = Na*k                     # molar gas constant\n\"    Unitful.σ\n\\nA quantity representing the Stefan-Boltzmann constant, defined as\nπ^2 × k^4 / (60 × ħ^3 × c^2).\n\\nDimension: 𝐌 𝚯^-4 𝐓^-3.\n\\nSee also: [`Unitful.k`](@ref), [`Unitful.ħ`](@ref), [`Unitful.c`](@ref).\"\nconst σ  = π^2*k^4/(60*ħ^3*c^2)     # Stefan-Boltzmann constant\n\"    Unitful.R∞\n\\nA quantity representing the Rydberg constant, equal to 1.097,373,156,8160 × 10^-7 / m\n(the CODATA 2018 recommended value).\n\\nDimension: 𝐋^-1.\n\\nSee also: [`Unitful.m`](@ref).\"\nconst R∞ = 10_973_731.568_160/m     # (21) Rydberg constant\n\"    Unitful.u\n\\nThe unified atomic mass unit, or dalton, a unit of mass defined as 1/12 the\nmass of an unbound neutral atom of carbon-12, equal to 1.660,539,066,60 × 10^-27 kg\n(the CODATA 2018 recommended value).\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee Also: [`Unitful.kg`](@ref).\"\n@unit u      \"u\" UnifiedAtomicMassUnit 1.660_539_066_60e-27*kg false # (50)\n\n# Acceleration\n\"    Unitful.ge\n\\nThe nominal acceleration due to gravity in a vacuum near the surface of the\nearth, a unit of acceleration, defined by standard to be exactly 9.806,65 m / s^2.\n\\n[`Unitful.gn`](@ref) is a quantity (with units `m/s^2`) whereas `Unitful.ge` is a unit equal to `gn`.\n\\nDimension: 𝐋 𝐓^-2.\n\\nSee also: [`Unitful.m`](@ref), [`Unitful.s`](@ref).\"\n@unit ge     \"ge\"       EarthGravity gn                     false\n\n\n# CGS units\n\"    Unitful.Gal\n\\nThe gal, a CGS unit of acceleration, defined as 1 cm / s^2.\n\\nDimension: 𝐋 𝐓^-2.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.s`](@ref).\"\n@unit Gal    \"Gal\"      Gal         1cm/s^2                 true true\n\"    Unitful.dyn\n\\nThe dyne, a CGS unit of force, defined as 1 g × cm / s^2.\n\\nDimension: 𝐋 𝐌 𝐓^-2.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.s`](@ref), [`Unitful.g`](@ref).\"\n@unit dyn    \"dyn\"      Dyne        1g*cm/s^2               true true\n\"    Unitful.erg\n\\nThe erg, a CGS unit of energy, defined as 1 dyn × cm.\n\\nDimension: 𝐋^2 𝐌 𝐓^-2.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.dyn`](@ref)\"\n@unit erg    \"erg\"      Erg         1g*cm^2/s^2             true true\n\"    Unitful.Ba\n\\nThe barye, a CGS unit of pressure, defined as 1 dyn / cm^2.\n\\nDimension: 𝐌 𝐋^-1 𝐓^-2.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.dyn`](@ref)\"\n@unit Ba     \"Ba\"       Barye       1g/cm/s^2               true true\n\"    Unitful.P\n\\nThe poise, a CGS unit of dynamic viscosity, defined as 1 dyn × s / cm^2.\n\\nDimension: 𝐌 𝐋^-1 𝐓^-1.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.dyn`](@ref), [`Unitful.s`](@ref)\"\n@unit P      \"P\"        Poise       1g/cm/s                 true true\n\"    Unitful.St\n\\nThe stokes, a CGS unit of kinematic viscosity, defined as 1 cm^2 / s.\n\\nDimension: 𝐌^2 𝐓^-1.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.s`](@ref)\"\n@unit St     \"St\"       Stokes      1cm^2/s                 true true\n\"    Unitful.Gauss\n\\nThe gauss, a CGS unit of magnetic B-field strength, defined as 1 Mx / cm^2.\n\\nDimension: 𝐌 𝐈^-1 𝐓^-2.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.Mx`](@ref)\"\n@unit Gauss  \"Gauss\"    Gauss       (1//10_000)*T           true true\n\"    Unitful.Oe\n\\nThe oersted, a CGS unit of magnetic H-field strength, defined as 1000 A / (4π × m).\n\\nDimension: 𝐈 𝐋^-1.\n\\nSee also: [`Unitful.A`](@ref), [`Unitful.m`](@ref)\"\n@unit Oe     \"Oe\"       Oersted     (1_000/4π)*A/m          true true\n\"    Unitful.Mx\n\\nThe maxwell, a CGS unit of magnetic flux, defined as 1 Gauss × cm^2.\n\\nDimension: 𝐋^2 𝐌 𝐈^-1 𝐓^-2.\n\\nSee also: [`Unitful.cm`](@ref), [`Unitful.Gauss`](@ref)\"\n@unit Mx     \"Mx\"       Maxwell     (1//100_000_000)*Wb     true true\n\n\n#########\n# Shared Imperial / US customary units\n\n# Length\n#key: Symbol    Display    Name                 Equivalent to           10^n prefixes?\n\"    Unitful.inch\n\\nThe inch, a US customary unit of length defined as 2.54 cm.\n\\nDimension: [`Unitful.𝐋`](@ref).\n\\nSee Also: [`Unitful.cm`](@ref).\"\n@unit inch      \"inch\"     Inch                 (254//10000)*m          false\n\"    Unitful.mil\n\\nThe mil, a US customary unit of length defined as 1/1000 inch.\n\\nDimension: [`Unitful.𝐋`](@ref).\n\\nSee Also: [`Unitful.inch`](@ref).\"\n@unit mil       \"mil\"      Mil                  (1//1000)*inch          false\n\"    Unitful.ft\n\\nThe foot, a US customary unit of length defined as 12 inch.\n\\nDimension: [`Unitful.𝐋`](@ref).\n\\nSee Also: [`Unitful.inch`](@ref).\"\n@unit ft        \"ft\"       Foot                 12inch                  false\n\"    Unitful.yd\n\\nThe yard, a US customary unit of length defined as 3 ft.\n\\nDimension: [`Unitful.𝐋`](@ref).\n\\nSee Also: [`Unitful.ft`](@ref).\"\n@unit yd        \"yd\"       Yard                 3ft                     false\n\"    Unitful.mi\n\\nThe mile, a US customary unit of length defined as 1760 yd.\n\\nDimension: [`Unitful.𝐋`](@ref).\n\\nSee Also: [`Unitful.yd`](@ref).\"\n@unit mi        \"mi\"       Mile                 1760yd                  false\n\"    Unitful.angstrom\n    Unitful.Å\n\\nThe angstrom, a metric unit of length defined as 1/10 nm.\n\\nDimension: [`Unitful.𝐋`](@ref).\n\\nSee Also: [`Unitful.nm`](@ref).\"\n((@unit angstrom \"Å\"       Angstrom             (1//10)*nm              false), const Å = angstrom)\n\n# Area\n\"    Unitful.ac\n\\nThe acre, a US customary unit of area defined as 4840 yd^2.\n\\nDimension: 𝐋^2.\n\\nSee Also: [`Unitful.yd`](@ref).\"\n@unit ac        \"ac\"       Acre                 (316160658//78125)*m^2  false\n\n# Temperatures\n\"    Unitful.Ra\n\\nThe rankine, a US customary unit of temperature defined as 5/9 K.\n\\nDimension: [`Unitful.𝚯`](@ref).\n\\nSee Also: [`Unitful.K`](@ref).\"\n@unit Ra        \"Ra\"      Rankine               (5//9)*K                false\n\"    Unitful.°F\n    Unitful.degF\n\\nThe degree Fahrenheit, a US customary unit of temperature, defined such that 0 °F = 459.67 Ra.\n\\nDimension: [`Unitful.𝚯`](@ref).\n\\nSee also: [`Unitful.Ra`](@ref).\"\n((@affineunit °F  \"°F\"      (45967//100)Ra), const degF = °F)\n\n# Masses\n\"    Unitful.lb\n\\nThe pound-mass, a US customary unit of mass defined as exactly 0.453,592,37 kg.\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee Also: [`Unitful.kg`](@ref).\"\n@unit lb        \"lb\"       Pound                0.45359237kg            false # is exact\n\"    Unitful.oz\n\\nThe ounce, a US customary unit of mass defined as 1/16 lb.\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee Also: [`Unitful.lb`](@ref).\"\n@unit oz        \"oz\"       Ounce                lb//16                  false\n\"    Unitful.slug\n\\nThe slug, a US customary unit of mass defined as 1 lbf × s^2 / ft.\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee Also: [`Unitful.lbf`](@ref), [`Unitful.s`](@ref), [`Unitful.ft`](@ref).\"\n@unit slug      \"slug\"     Slug                 1lb*ge*s^2/ft           false\n\"    Unitful.dr\n\\nThe dram, a US customary unit of mass defined as 1/16 oz.\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee Also: [`Unitful.oz`](@ref).\"\n@unit dr        \"dr\"       Dram                 oz//16                  false\n\"    Unitful.gr\n\\nThe grain, a US customary unit of mass defined as 1/7000 lb.\n\\nDimension: [`Unitful.𝐌`](@ref).\n\\nSee Also: [`Unitful.lb`](@ref).\"\n@unit gr        \"gr\"       Grain                (32//875)*dr            false\n\n# Force\n\"    Unitful.lbf\n\\nThe pound-force, a US customary unit of force defined as 1 lb × ge.\n\\nDimension: 𝐋 𝐌 𝐓^-2.\n\\nSee Also: [`Unitful.lb`](@ref), [`Unitful.ge`](@ref).\"\n@unit lbf       \"lbf\"      PoundsForce          1lb*ge                  false\n\n# Energy\n# Use ISO 31-4 for BTU definition\n\"    Unitful.cal\n\\nThe calorie, a unit of energy defined as exactly 4.184 J.\n\\nDimension: 𝐋^2 𝐌 𝐓^-2.\n\\nSee Also: [`Unitful.J`](@ref).\"\n@unit cal       \"cal\"      Calorie              4.184J                  true true\n\"    Unitful.btu\n\\nThe British thermal unit, a US customary unit of heat defined by ISO 31-4 as exactly 1055.06 J.\n\\nDimension: 𝐋^2 𝐌 𝐓^-2.\n\\nSee Also: [`Unitful.J`](@ref).\"\n@unit btu       \"btu\"      BritishThermalUnit   1055.06J                false\n\n# Pressure\n\"    Unitful.psi\n\\nPounds per square inch, a US customary unit of pressure defined as 1 lbf / inch^2.\n\\nDimension: 𝐌 𝐋^-1 𝐓^-2.\n\\nSee Also: [`Unitful.lbf`](@ref), [`Unitful.inch`](@ref).\"\n@unit psi       \"psi\"      PoundsPerSquareInch  1lbf/inch^2             false\n\n#########\n# Logarithmic scales and units\n\n@logscale dB    \"dB\"       Decibel      10      10      false\n@logscale B     \"B\"        Bel          10      1       false\n@logscale Np    \"Np\"       Neper        ℯ       1//2    true\n@logscale cNp   \"cNp\"      Centineper   ℯ       50      true\n\n@logunit  dBHz  \"dB-Hz\"    Decibel      1Hz\n@logunit  dBm   \"dBm\"      Decibel      1mW\n@logunit  dBV   \"dBV\"      Decibel      1V\n@logunit  dBu   \"dBu\"      Decibel      sqrt(0.6)V\n@logunit  dBμV  \"dBμV\"     Decibel      1μV\n@logunit  dBSPL \"dBSPL\"    Decibel      20μPa\n@logunit  dBFS  \"dBFS\"     Decibel      RootPowerRatio(1)\n@logunit  dBΩ   \"dBΩ\"      Decibel      1Ω\n@logunit  dBS   \"dBS\"      Decibel      1S\n\n# TODO: some more dimensions?\nisrootpower_dim(::typeof(dimension(W)))         = false\nisrootpower_dim(::typeof(dimension(V)))         = true\nisrootpower_dim(::typeof(dimension(A)))         = true\nisrootpower_dim(::typeof(dimension(Pa)))        = true\nisrootpower_dim(::typeof(dimension(W/m^2/Hz)))  = false     # spectral flux dens.\nisrootpower_dim(::typeof(dimension(W/m^2)))     = false     # intensity\nisrootpower_dim(::typeof(dimension(W/m^2/m)))   = false\nisrootpower_dim(::typeof(𝐋^3))                  = false     # reflectivity\nisrootpower_dim(::typeof(dimension(Ω)))         = true\nisrootpower_dim(::typeof(dimension(S)))         = true\nisrootpower_dim(::typeof(dimension(Hz)))        = false\nisrootpower_dim(::typeof(dimension(J)))         = false\n\n#########\n\n# `using Unitful.DefaultSymbols` will bring the following into the calling namespace:\n# - Dimensions 𝐋,𝐌,𝐓,𝐈,𝚯,𝐉,𝐍\n# - Base and derived SI units, with SI prefixes\n#   - Candela conflicts with `Base.cd` so it is not brought in (issue #102)\n# - Degrees: °\n\nconst si_prefixes = (:y, :z, :a, :f, :p, :n, :μ, :m, :c, :d,\n    Symbol(\"\"), :da, :h, :k, :M, :G, :T, :P, :E, :Z, :Y)\n\nconst si_no_prefix = (:m, :s, :A, :K, :g, :mol, :rad, :sr, :Hz, :N, :Pa, #:cd,\n    :J, :W, :C, :V, :F, :Ω, :S, :Wb, :T, :H, :lm, :lx, :Bq, :Gy, :Sv, :kat)\n\nbaremodule DefaultSymbols\n    import Unitful\n\n    for u in (:𝐋,:𝐌,:𝐓,:𝐈,:𝚯,:𝐉,:𝐍)\n        Core.eval(DefaultSymbols, Expr(:import, Expr(:(.), :Unitful, u)))\n        Core.eval(DefaultSymbols, Expr(:export, u))\n    end\n\n    for p in Unitful.si_prefixes\n        for u in Unitful.si_no_prefix\n            Core.eval(DefaultSymbols, Expr(:import, Expr(:(.), :Unitful, Symbol(p,u))))\n            Core.eval(DefaultSymbols, Expr(:export, Symbol(p,u)))\n        end\n    end\n\n    Core.eval(DefaultSymbols, Expr(:import, Expr(:(.), :Unitful, :°C)))\n    Core.eval(DefaultSymbols, Expr(:export, :°C))\n\n    Core.eval(DefaultSymbols, Expr(:import, Expr(:(.), :Unitful, :°)))\n    Core.eval(DefaultSymbols, Expr(:export, :°))\nend\n\n#########\n\npreferunits(kg) # others done in @refunit\n# Fix documentation for all kg based units\nfor (k,v) in prefixdict\n    if k != 3\n        sym = Symbol(v,:g)\n        docstring = \"\"\"\n                        Unitful.$sym\n\n                    A prefixed unit, equal to 10^$(k-3) kg. Note that `kg`, not `g`, is the base unit.\n\n                    Dimension: [`Unitful.𝐌`](@ref).\n\n                    See also: [`Unitful.kg`](@ref).\n                    \"\"\"\n        run = quote @doc $docstring $sym end\n        eval(run)\n    end\nend\n@doc \"    Unitful.kg\n\\nThe kilogram, the SI base unit of mass.\nNote that `kg`, not `g`, is the base unit.\n\\nDimension: [`Unitful.𝐌`](@ref).\" kg\n\n\"\"\"\n    Unitful.promote_to_derived()\nDefines promotion rules to use derived SI units in promotion for common dimensions\nof quantities:\n\n- `J` (joule) for energy\n- `N` (newton) for force\n- `W` (watt) for power\n- `Pa` (pascal) for pressure\n- `C` (coulomb) for charge\n- `V` (volt) for voltage\n- `Ω` (ohm) for resistance\n- `F` (farad) for capacitance\n- `H` (henry) for inductance\n- `Wb` (weber) for magnetic flux\n- `T` (tesla) for B-field\n- `J*s` (joule-second) for action\n\nIf you want this as default behavior (it was for versions of Unitful prior to 0.1.0),\nconsider invoking this function in your `startup.jl` file which is loaded when\nyou open Julia. This function is not exported.\n\"\"\"\nfunction promote_to_derived()\n    eval(quote\n         Unitful.promote_unit(::S, ::T) where\n         {S<:EnergyFreeUnits, T<:EnergyFreeUnits} = Unitful.J\n         Unitful.promote_unit(::S, ::T) where\n         {S<:ForceFreeUnits, T<:ForceFreeUnits} = Unitful.N\n         Unitful.promote_unit(::S, ::T) where\n         {S<:PowerFreeUnits, T<:PowerFreeUnits} = Unitful.W\n         Unitful.promote_unit(::S, ::T) where\n         {S<:PressureFreeUnits, T<:PressureFreeUnits} = Unitful.Pa\n         Unitful.promote_unit(::S, ::T) where\n         {S<:ChargeFreeUnits, T<:ChargeFreeUnits} = Unitful.C\n         Unitful.promote_unit(::S, ::T) where\n         {S<:VoltageFreeUnits, T<:VoltageFreeUnits} = Unitful.V\n         Unitful.promote_unit(::S, ::T) where\n         {S<:ElectricalResistanceFreeUnits, T<:ElectricalResistanceFreeUnits} = Unitful.Ω\n         Unitful.promote_unit(::S, ::T) where\n         {S<:CapacitanceFreeUnits, T<:CapacitanceFreeUnits} = Unitful.F\n         Unitful.promote_unit(::S, ::T) where\n         {S<:InductanceFreeUnits, T<:InductanceFreeUnits} = Unitful.H\n         Unitful.promote_unit(::S, ::T) where\n         {S<:MagneticFluxFreeUnits, T<:MagneticFluxFreeUnits} = Unitful.Wb\n         Unitful.promote_unit(::S, ::T) where\n         {S<:BFieldFreeUnits, T<:BFieldFreeUnits} = Unitful.T\n         Unitful.promote_unit(::S, ::T) where\n         {S<:ActionFreeUnits, T<:ActionFreeUnits} = Unitful.J * Unitful.s\n        end)\n    nothing\nend\n"
  },
  {
    "path": "src/promotion.jl",
    "content": "\"\"\"\n    promote_unit(::Units, ::Units...)\nGiven `Units` objects as arguments, this function returns a `Units` object appropriate\nfor the result of promoting quantities which have these units. This function is kind\nof like `promote_rule`, except that it doesn't take types. It also does not return a tuple,\nbut rather just a [`Unitful.Units`](@ref) object (or it throws an error).\n\nAlthough we had used `promote_rule` for `Units` objects in prior versions of Unitful,\nthis was always kind of a hack; it doesn't make sense to promote units directly for\na variety of reasons.\n\"\"\"\nfunction promote_unit end\n\n# Generic methods\n@inline promote_unit(x) = _promote_unit(x)\n@inline _promote_unit(x::Units) = x\n\n@inline promote_unit(x,y) = _promote_unit(x,y)\n\npromote_unit(x::Units, y::Units, z::Units, t::Units...) =\n    promote_unit(_promote_unit(x,y), z, t...)\n\n@inline _promote_unit(x::T, y::T) where {T <: FreeUnits} = T()\n# Use configurable fall-back mechanism for FreeUnits\n@inline _promote_unit(x::FreeUnits{N1,D}, y::FreeUnits{N2,D}) where {N1,N2,D} =\n    upreferred(dimension(x))\n\n@inline _promote_unit(x::ContextUnits{N,D,P,A}, y::ContextUnits{N,D,P,A}) where {N,D,P,A} = x  #ambiguity reasons\n# same units, but promotion context disagrees\n@inline _promote_unit(x::ContextUnits{N,D,P1,A}, y::ContextUnits{N,D,P2,A}) where {N,D,P1,P2,A} =\n    ContextUnits{N,D,promote_unit(P1(), P2()),A}()\n# different units, but promotion context agrees\n@inline _promote_unit(x::ContextUnits{N1,D,P}, y::ContextUnits{N2,D,P}) where {N1,N2,D,P} =\n    ContextUnits(P(), P())\n# different units, promotion context disagrees, fall back to FreeUnits\n@inline _promote_unit(x::ContextUnits{N1,D,P1}, y::ContextUnits{N2,D,P2}) where {N1,N2,D,P1,P2} =\n    promote_unit(FreeUnits(x), FreeUnits(y))\n\n# ContextUnits beat FreeUnits\n@inline _promote_unit(x::ContextUnits{N,D,P,A}, y::FreeUnits{N,D,A}) where {N,D,P,A} = x\n@inline _promote_unit(x::ContextUnits{N,D,P,A1}, y::FreeUnits{N,D,A2}) where {N,D,P,A1,A2} =\n    ContextUnits(P(), P())\n@inline _promote_unit(x::ContextUnits{N1,D,P}, y::FreeUnits{N2,D}) where {N1,N2,D,P} =\n    ContextUnits(P(), P())\n@inline _promote_unit(x::FreeUnits, y::ContextUnits) = promote_unit(y,x)\n\n# FixedUnits beat everything\n@inline _promote_unit(x::T, y::T) where {T <: FixedUnits} = T()\n@inline _promote_unit(x::FixedUnits{M,D}, y::Units{N,D}) where {M,N,D} = x\n@inline _promote_unit(x::Units, y::FixedUnits) = promote_unit(y,x)\n\n# Different units but same dimension are not fungible for FixedUnits\n@inline _promote_unit(x::FixedUnits{M,D}, y::FixedUnits{N,D}) where {M,N,D} =\n    error(\"automatic conversion prohibited.\")\n\n# If we didn't handle it above, the dimensions mismatched.\n@inline _promote_unit(x::Units, y::Units) = throw(DimensionError(x,y))\n\n####\n#    Base.promote_rule\n\n# quantity, quantity (different dims)\nBase.promote_rule(::Type{Quantity{S1,D1,U1}},\n        ::Type{Quantity{S2,D2,U2}}) where {S1,D1,U1,S2,D2,U2} =\n    Quantity{promote_type(S1,S2)}\n\n# quantity, quantity (same dims, different units)\nfunction Base.promote_rule(::Type{Quantity{S1,D,U1}},\n        ::Type{Quantity{S2,D,U2}}) where {S1,S2,D,U1,U2}\n\n    p = promote_unit(U1(), U2())\n    c1 = convfact(p, U1())\n    c1′ = affinetranslation(U1())\n    c2 = convfact(p, U2())\n    c2′ = affinetranslation(U2())\n    numtype = promote_type(S1, S2,\n        promote_type(typeof(c1), typeof(c2), typeof(c1′), typeof(c2′)))\n    if !isunitless(p)\n        if U1 <: ContextUnits && U2 <: ContextUnits\n            up1 = upreferred(U1())\n            if up1 === upreferred(U2())\n                return Quantity{numtype,D,typeof(ContextUnits(p,up1))}\n            else\n                return Quantity{numtype,D,typeof(p)}\n            end\n        elseif U1 <: ContextUnits || U2 <: ContextUnits\n            return Quantity{numtype,D,typeof(ContextUnits(p,p))}\n        else\n            return Quantity{numtype,D,typeof(p)}\n        end\n    else\n        return numtype\n    end\nend\n\n# number, quantity\nfunction Base.promote_rule(::Type{Quantity{S,D,U}}, ::Type{T}) where {S,T <: Number,D,U}\n    if D == NoDims\n        promote_type(S,T,typeof(convfact(NoUnits,U())))\n    else\n        Quantity{promote_type(S,T)}\n    end\nend\n\nBase.promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational,S2,T<:Quantity{S2}} =\n    promote_type(promote_type(S, real(S2)), T)\n\nBase.promote_rule(::Type{Quantity{S}}, ::Type{T}) where {S,T <: Number} =\n    Quantity{promote_type(S,T)}\n\n# With only one of these, you can get a segmentation fault because you # fall back to the\n# number, quantity promote_rule above and there is an infinite recursion.\nBase.promote_rule(::Type{Quantity{T}}, ::Type{Quantity{S,D,U}}) where {T,S,D,U} =\n    Quantity{promote_type(T,S)}\n\nBase.promote_rule(::Type{Quantity{S,D,U}}, ::Type{Quantity{T}}) where {T,S,D,U} =\n    Quantity{promote_type(T,S)}\n"
  },
  {
    "path": "src/quantities.jl",
    "content": "# This is a generated function to avoid determining the dimensions of a given\n# set of units each time a new quantity is made.\n@generated function _Quantity(x::Number, y::Units)\n    u = y()\n    du = dimension(u)\n    dx = dimension(x)\n    d = du*dx\n    :(Quantity{typeof(x), $d, typeof($u)}(x))\nend\n\n\"\"\"\n    Quantity(x::Number, y::Units)\n\nCreate a `Quantity` with numerical value `x` and units `y`.\n\n# Example\n\n```jldoctest\njulia> Quantity(5, u\"m\")\n5 m\n```\n\"\"\"\nQuantity(x::Number, y::Units) = _Quantity(x, y)\nQuantity(x::Number, y::Units{()}) = x\n\n*(x::Number, y::Units, z::Units...) = Quantity(x,*(y,z...))\n*(x::Units, y::Number) = *(y,x)\n\n*(x::AbstractQuantity, y::Units, z::Units...) = Quantity(x.val, *(unit(x),y,z...))\n*(x::AbstractQuantity, y::AbstractQuantity) = Quantity(x.val*y.val, unit(x)*unit(y))\n\nfunction *(x::Number, y::AbstractQuantity)\n    y isa AffineQuantity &&\n        throw(AffineError(\"an invalid operation was attempted with affine quantities: $x*$y\"))\n    return Quantity(x*y.val, unit(y))\nend\nfunction *(x::AbstractQuantity, y::Number)\n    x isa AffineQuantity &&\n        throw(AffineError(\"an invalid operation was attempted with affine quantities: $x*$y\"))\n    return Quantity(x.val*y, unit(x))\nend\n\n*(A::Units, B::AbstractArray) = broadcast(*, A, B)\n*(A::AbstractArray, B::Units) = broadcast(*, A, B)\n\n/(A::AbstractArray, B::Units) = broadcast(/, A, B)\n\n# Division (units)\n/(x::AbstractQuantity, y::Units) = Quantity(x.val, unit(x) / y)\n/(x::Units, y::AbstractQuantity) = Quantity(1/y.val, x / unit(y))\n/(x::Number, y::Units) = Quantity(x,inv(y))\n/(x::Units, y::Number) = (1/y) * x\n\n//(x::AbstractQuantity, y::Units) = Quantity(x.val, unit(x) / y)\n//(x::Units, y::AbstractQuantity) = Quantity(1//y.val, x / unit(y))\n//(x::Number, y::Units) = Rational(x)/y\n//(x::Units, y::Number) = (1//y) * x\n\n/(x::AbstractQuantity, y::AbstractQuantity) = Quantity(/(x.val, y.val), unit(x) / unit(y))\n/(x::AbstractQuantity, y::Number) = Quantity(/(x.val, y), unit(x) / unit(y))\n/(x::Number, y::AbstractQuantity) = Quantity(/(x, y.val), unit(x) / unit(y))\n//(x::AbstractQuantity, y::AbstractQuantity) = Quantity(//(x.val, y.val), unit(x) / unit(y))\n//(x::AbstractQuantity, y::Number) = Quantity(//(x.val, y), unit(x) // unit(y))\n//(x::Number, y::AbstractQuantity) = Quantity(//(x, y.val), unit(x) / unit(y))\n\n# ambiguity resolution\n//(x::AbstractQuantity, y::Complex) = Quantity(//(x.val, y), unit(x))\n\nfor f in (:fld, :cld)\n    @eval begin\n        function ($f)(x::AbstractQuantity, y::AbstractQuantity)\n            z = uconvert(unit(y), x)        # TODO: use promote?\n            ($f)(z.val,y.val)\n        end\n\n        ($f)(x::Number, y::AbstractQuantity) = Quantity(($f)(x, ustrip(y)), unit(x) / unit(y))\n\n        ($f)(x::AbstractQuantity, y::Number) = Quantity(($f)(ustrip(x), y), unit(x))\n    end\nend\n\nfunction div(x::AbstractQuantity, y::AbstractQuantity, r...)\n    z = uconvert(unit(y), x)        # TODO: use promote?\n    div(z.val,y.val, r...)\nend\n\nfunction div(x::Number, y::AbstractQuantity, r...)\n    Quantity(div(x, ustrip(y), r...), unit(x) / unit(y))\nend\n\nfunction div(x::AbstractQuantity, y::Number, r...)\n    Quantity(div(ustrip(x), y, r...), unit(x))\nend\n\nfor f in (:mod, :rem)\n    @eval function ($f)(x::AbstractQuantity, y::AbstractQuantity)\n        z = uconvert(unit(y), x)        # TODO: use promote?\n        Quantity(($f)(z.val,y.val), unit(y))\n    end\nend\n\n_affineerror(f, args...) =\n    throw(AffineError(\"an invalid operation was attempted with affine quantities: $f($(join(args, \", \")))\"))\n\nfor f in (:div, :rem, :divrem)\n    for r = (RoundNearest, RoundNearestTiesAway, RoundNearestTiesUp,\n             RoundToZero, RoundUp, RoundDown)\n        @eval begin\n            $f(x::AffineQuantity, y::AffineQuantity, ::typeof($r)) = _affineerror($f, x, y, $r)\n            $f(x::AffineQuantity, y::AbstractQuantity, ::typeof($r)) = _affineerror($f, x, y, $r)\n            $f(x::AbstractQuantity, y::AffineQuantity, ::typeof($r)) = _affineerror($f, x, y, $r)\n        end\n    end\nend\nfor f = (:div, :cld, :fld, :rem, :mod)\n    @eval begin\n        $f(x::AffineQuantity, y::AffineQuantity) = _affineerror($f, x, y)\n        $f(x::AffineQuantity, y::AbstractQuantity) = _affineerror($f, x, y)\n        $f(x::AbstractQuantity, y::AffineQuantity) = _affineerror($f, x, y)\n    end\nend\n\nBase.mod2pi(x::DimensionlessQuantity) = mod2pi(uconvert(NoUnits, x))\nBase.mod2pi(x::AbstractQuantity{S, NoDims, <:Units{(Unitful.Unit{:Degree, NoDims}(0, 1//1),),\n    NoDims}}) where S = mod(x, 360°)\nBase.modf(x::DimensionlessQuantity) = modf(uconvert(NoUnits, x))\n\n# Addition / subtraction\nfor op in [:+, :-]\n    @eval ($op)(x::AbstractQuantity{S,D,U}, y::AbstractQuantity{T,D,U}) where {S,T,D,U} =\n        Quantity(($op)(x.val, y.val), U())\n\n    @eval function ($op)(x::AbstractQuantity{S,D,SU}, y::AbstractQuantity{T,D,TU}) where {S,T,D,SU,TU}\n        ($op)(promote(x,y)...)\n    end\n\n    @eval ($op)(x::AbstractQuantity, y::AbstractQuantity) = throw(DimensionError(x,y))\n    @eval ($op)(x::AbstractQuantity) = Quantity(($op)(x.val), unit(x))\nend\n\nfunction +(x::AffineQuantity{S,D}, y::AbstractQuantity{T,D}) where {S,T,D}\n    pu = promote_unit(unit(x), unit(y))     # units for the final result.\n\n    # Get x on an absolute scale. FreeUnits in the line below prevents\n    # promote(x′, y) from yielding affine quantities. If x had `ContextUnits` and\n    # the promotion units were affine units, x′+y would error without this.\n    x′ = Quantity(x.val - affinetranslation(unit(x)), FreeUnits(absoluteunit(x)))\n\n    # Likewise if y were not affine but y had ContextUnits and the promotion units were\n    # affine, x′+y could also fail.\n    y′ = Quantity(y.val, FreeUnits(unit(y)))\n\n    return uconvert(pu, x′+y′)  # we get back the promotion context in the end\nend\n+(x::AbstractQuantity, y::AffineQuantity) = +(y,x)\n\n# Disallow addition of affine quantities\n+(x::AffineQuantity, y::AffineQuantity) = throw(AffineError(\n   \"an invalid operation was attempted with affine quantities: $x + $y\"))\n\n# Specialize subtraction of affine quantities\n-(x::AffineQuantity, y::AffineQuantity) = -(promote(x,y)...)\nfunction -(x::T, y::T) where T <: AffineQuantity\n    return Quantity(x.val - y.val, absoluteunit(unit(x)))\nend\n\n# Disallow subtracting an affine quantity from a quantity\n-(x::AbstractQuantity, y::AffineQuantity) =\n    throw(AffineError(\"an invalid operation was attempted with affine quantities: $x - $y\"))\n\n# Needed until LU factorization is made to work with unitful numbers\nfunction inv(x::StridedMatrix{T}) where {T <: AbstractQuantity}\n    m = inv(ustrip(x))\n    iq = eltype(m)\n    reinterpret(Quantity{iq, inv(dimension(T)), typeof(inv(unit(T)))}, m)\nend\n\n# Other mathematical functions\n\n# `fma` and `muladd`\n# The idea here is that if the numeric backing types are not the same, they\n# will be promoted to be the same by the generic `fma(::Number, ::Number, ::Number)`\n# method. We then catch the possible results and handle the units logic with one\n# performant method.\n\nfor (_x,_y) in [(:fma, :_fma), (:muladd, :_muladd)]\n    # Catch some signatures pre-promotion\n    @eval @inline ($_x)(x::Number, y::AbstractQuantity, z::AbstractQuantity) = ($_y)(x,y,z)\n    @eval @inline ($_x)(x::AbstractQuantity, y::Number, z::AbstractQuantity) = ($_y)(x,y,z)\n\n    # Post-promotion\n    @eval @inline ($_x)(x::AbstractQuantity, y::AbstractQuantity, z::AbstractQuantity) = ($_y)(x,y,z)\n\n    # It seems like most of this is optimized out by the compiler, including the\n    # apparent runtime check of dimensions, which does not appear in @code_llvm.\n    @eval @inline function ($_y)(x,y,z)\n        dimension(x) * dimension(y) != dimension(z) && throw(DimensionError(x*y,z))\n        uI = unit(x)*unit(y)\n        uF = promote_unit(uI, unit(z))\n        c = ($_x)(ustrip(x), ustrip(y), ustrip(uconvert(uI, z)))\n        uconvert(uF, Quantity(c, uI))\n    end\nend\n\nsqrt(x::AbstractQuantity) = Quantity(sqrt(x.val), sqrt(unit(x)))\ncbrt(x::AbstractQuantity) = Quantity(cbrt(x.val), cbrt(unit(x)))\n\nfor _y in (:sin, :cos, :tan, :asin, :acos, :atan, :sinh, :cosh, :tanh, :asinh, :acosh, :atanh,\n           :sinpi, :cospi, :tanpi, :sinc, :cosc, :sincos, :sincospi)\n    if isdefined(Base, _y)\n        @eval Base.$(_y)(x::DimensionlessQuantity) = Base.$(_y)(uconvert(NoUnits, x))\n    end\nend\ncis(x::DimensionlessQuantity{<:Real}) = Complex(reverse(sincos(x))...)\ncis(x::DimensionlessQuantity{<:Complex}) = exp(-imag(x)) * cis(real(x))\ncispi(x::DimensionlessQuantity{<:Real}) = Complex(reverse(sincospi(x))...)\ncispi(x::DimensionlessQuantity{<:Complex}) = exp(-(π*imag(x))) * cispi(real(x))\n\natan(y::AbstractQuantity{T1,D,U1}, x::AbstractQuantity{T2,D,U2}) where {T1,T2,D,U1,U2} =\n    atan(promote(y,x)...)\natan(y::AbstractQuantity{T,D,U}, x::AbstractQuantity{T,D,U}) where {T,D,U} = atan(y.val,x.val)\natan(y::AbstractQuantity, x::AbstractQuantity) = throw(DimensionError(x,y))\n\nabs(x::AbstractQuantity) = Quantity(abs(x.val), unit(x))\nabs2(x::AbstractQuantity) = Quantity(abs2(x.val), unit(x)*unit(x))\nangle(x::AbstractQuantity{<:Complex}) = angle(x.val)\n\ncopysign(x::AbstractQuantity, y::Number) = Quantity(copysign(x.val,y/unit(y)), unit(x))\ncopysign(x::Number, y::AbstractQuantity) = copysign(x,y/unit(y))\ncopysign(x::AbstractQuantity, y::AbstractQuantity) = Quantity(copysign(x.val,y/unit(y)), unit(x))\n\nflipsign(x::AbstractQuantity, y::Number) = Quantity(flipsign(x.val,y/unit(y)), unit(x))\nflipsign(x::Number, y::AbstractQuantity) = flipsign(x,y/unit(y))\nflipsign(x::AbstractQuantity, y::AbstractQuantity) = Quantity(flipsign(x.val,y/unit(y)), unit(x))\n\nfor (i,j) in zip((:<, :<=, :isless), (:_lt, :_le, :_isless))\n    @eval ($i)(x::AbstractQuantity, y::AbstractQuantity) = ($j)(x,y)\n    @eval ($i)(x::AbstractQuantity, y::Number) = ($i)(promote(x,y)...)\n    @eval ($i)(x::Number, y::AbstractQuantity) = ($i)(promote(x,y)...)\n\n    # promotion might not yield Quantity types\n    @eval @inline ($j)(x::AbstractQuantity{T1}, y::AbstractQuantity{T2}) where {T1,T2} = ($i)(promote(x,y)...)\n    # If it does yield Quantity types, we'll get back here,\n    # since at least the numeric part can be promoted.\n    @eval @inline ($j)(x::AbstractQuantity{T,D,U}, y::AbstractQuantity{T,D,U}) where {T,D,U} = ($i)(x.val,y.val)\n    @eval @inline ($j)(x::AbstractQuantity{T,D,U1}, y::AbstractQuantity{T,D,U2}) where {T,D,U1,U2} = ($i)(promote(x,y)...)\n    @eval @inline ($j)(x::AbstractQuantity{T,D1,U1}, y::AbstractQuantity{T,D2,U2}) where {T,D1,D2,U1,U2} = throw(DimensionError(x,y))\nend\n\nBase.rtoldefault(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U} = Base.rtoldefault(T)\n\nfunction isapprox(\n    x::AbstractQuantity{T,D,U},\n    y::AbstractQuantity{T,D,U};\n    atol = zero(Quantity{real(T),D,U}),\n    kwargs...,\n) where {T,D,U}\n    return isapprox(x.val, y.val; atol=ustrip(unit(y), atol), kwargs...)\nend\n\nfunction isapprox(x::AbstractQuantity, y::AbstractQuantity; kwargs...)\n    dimension(x) != dimension(y) && return false\n    return isapprox(promote(x,y)...; kwargs...)\nend\n\nfunction isapprox(x::AbstractQuantity, y::Number; atol=nothing, kwargs...)\n    if atol === nothing\n        return isapprox(promote(x, y)...; kwargs...)\n    end\n    xp, yp, atolp = promote(x, y, atol)\n    return isapprox(xp, yp; atol=atolp, kwargs...)\nend\nisapprox(x::Number, y::AbstractQuantity; kwargs...) = isapprox(y, x; kwargs...)\n\nfunction isapprox(\n    x::AbstractArray{<:AbstractQuantity{T1,D,U1}},\n    y::AbstractArray{<:AbstractQuantity{T2,D,U2}};\n    atol=zero(Quantity{real(T1),D,U1}),\n    rtol::Real=Base.rtoldefault(T1,T2,atol>zero(atol)),\n    nans::Bool=false,\n    norm::Function=norm,\n) where {T1,D,U1,T2,U2}\n    d = norm(x - y)\n    if isfinite(d)\n        return iszero(rtol) ? d <= atol : d <= max(atol, rtol*max(norm(x), norm(y)))\n    else\n        # Fall back to a component-wise approximate comparison\n        return all(ab -> isapprox(ab[1], ab[2]; rtol=rtol, atol=atol, nans=nans), zip(x, y))\n    end\nend\n\nisapprox(x::AbstractArray{S}, y::AbstractArray{T};\n    kwargs...) where {S <: AbstractQuantity,T <: AbstractQuantity} = false\n\nfunction isapprox(x::AbstractArray{S}, y::AbstractArray{N};\n    atol=nothing, kwargs...) where {S <: AbstractQuantity,N <: Number}\n    if dimension(N) == dimension(S)\n        if atol === nothing\n            isapprox(map(x->uconvert(NoUnits,x),x), y; kwargs...)\n        else\n            isapprox(map(x->uconvert(NoUnits,x),x), y; atol = ustrip(NoUnits, atol), kwargs...)\n        end\n    else\n        false\n    end\nend\n\nisapprox(y::AbstractArray{N}, x::AbstractArray{S};\n    kwargs...) where {S <: AbstractQuantity,N <: Number} = isapprox(x,y; kwargs...)\n\nfor cmp in [:(==), :isequal]\n    @eval $cmp(x::AbstractQuantity{S,D,U}, y::AbstractQuantity{T,D,U}) where {S,T,D,U} = $cmp(x.val, y.val)\n    @eval function $cmp(x::AbstractQuantity, y::AbstractQuantity)\n        dimension(x) != dimension(y) && return false\n        $cmp(promote(x,y)...)\n    end\n\n    @eval function $cmp(x::AbstractQuantity, y::Number)\n        $cmp(promote(x,y)...)\n    end\n    @eval $cmp(x::Number, y::AbstractQuantity) = $cmp(y,x)\nend\n\n# For now, hashes of quantities that are equal but have different units are not equal\nfunction hash(x::AbstractQuantity, h::UInt)\n    hash(x.val, hash(FreeUnits(unit(x)), h))\nend\n\n_dimerr(f) = error(\"$f can only be well-defined for dimensionless \",\n        \"numbers. For dimensionful numbers, different input units yield physically \",\n        \"different results.\")\nfor f in [:isinteger, :iseven, :isodd]\n    @eval $f(x::AbstractQuantity) = _dimerr($f)\n    @eval $f(x::DimensionlessQuantity) = $f(uconvert(NoUnits, x))\nend\n\n_rounderr() = error(\"specify the type of the quantity to convert to \",\n    \"when rounding quantities. Example: round(typeof(1u\\\"m\\\"), 137u\\\"cm\\\").\")\n\n# convenience methods\nround(u::Units, q::AbstractQuantity, r::RoundingMode=RoundNearest; kwargs...) =\n    Quantity(round(ustrip(u, q), r; kwargs...), u)\nround(::Type{T}, u::Units, q::AbstractQuantity, r::RoundingMode=RoundNearest;\n        kwargs...) where {T<:Number} =\n    round(Quantity{T, dimension(u), typeof(u)}, q, r; kwargs...)\n\n# workhorse methods\nround(x::AbstractQuantity, r::RoundingMode=RoundNearest; kwargs...) =\n    _rounderr()\nround(x::DimensionlessQuantity; kwargs...) = round(uconvert(NoUnits, x); kwargs...)\nround(x::DimensionlessQuantity, r::RoundingMode; kwargs...) =\n    round(uconvert(NoUnits, x), r; kwargs...)\nround(::Type{T}, x::AbstractQuantity, r::RoundingMode=RoundNearest;\n    kwargs...) where {T<:Number} = _dimerr(:round)\nround(::Type{T}, x::DimensionlessQuantity, r::RoundingMode=RoundNearest;\n    kwargs...) where {T<:Number} = round(T, uconvert(NoUnits, x), r; kwargs...)\nfunction round(::Type{T}, x::AbstractQuantity;\n        kwargs...) where {S, T <: Quantity{S}}\n    u = unit(T)\n    unitless = ustrip(u, x)\n    return Quantity{S, dimension(T), typeof(u)}(round(unitless; kwargs...))\nend\nfunction round(::Type{T}, x::AbstractQuantity, r::RoundingMode;\n        kwargs...) where {S, T <: Quantity{S}}\n    u = unit(T)\n    unitless = ustrip(u, x)\n    return Quantity{S, dimension(T), typeof(u)}(round(unitless, r; kwargs...))\nend\nround(::Type{T}, x::DimensionlessQuantity; kwargs...) where {S, T <: Quantity{S}} =\n    invoke(round, Tuple{Type{T},AbstractQuantity}, T, x; kwargs...) # for ambiguity resolution\nround(::Type{T}, x::DimensionlessQuantity, r::RoundingMode; kwargs...) where {S, T <: Quantity{S}} =\n    invoke(round, Tuple{Type{T},AbstractQuantity,RoundingMode}, T, x, r; kwargs...) # for ambiguity resolution\n\n# that should actually be fixed in Base ↓\nfor (f,r) = ((:trunc, :RoundToZero), (:floor, :RoundDown), (:ceil, :RoundUp))\n    @eval $f(x::AbstractQuantity; kwargs...) = round(x, $r; kwargs...)\n    @eval $f(::Type{T}, x::AbstractQuantity; kwargs...) where {T<:Number} =\n        round(T, x, $r; kwargs...)\n    @eval $f(u::Units, x::AbstractQuantity; kwargs...) = round(u, x, $r; kwargs...)\nend\n\nzero(x::AbstractQuantity) = Quantity(zero(x.val), unit(x))\nzero(x::AffineQuantity) = Quantity(zero(x.val), absoluteunit(x))\nzero(x::Type{<:AbstractQuantity{T}}) where {T} = throw(ArgumentError(\"zero($x) not defined.\"))\nzero(x::Type{<:AbstractQuantity{T,D}}) where {T,D} = zero(T) * upreferred(D)\nzero(x::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U<:ScalarUnits} = zero(T)*U()\nzero(x::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U<:AffineUnits} = zero(T)*absoluteunit(U())\n\nfunction zero(x::AbstractArray{T}) where T<:AbstractQuantity\n    if isconcretetype(T)\n        z = zero(T)\n        fill!(similar(x, typeof(z)), z)\n    else\n        dest = similar(x)\n        for i = eachindex(x)\n            if isassigned(x, i...)\n                dest[i] = zero(x[i])\n            else\n                dest[i] = zero(T)\n            end\n        end\n        dest\n    end\nend\n@static if VERSION < v\"1.8.0-DEV.107\"\n    function zero(x::AbstractArray{Union{T,Missing}}) where T<:AbstractQuantity # only matches _concrete_ T ...\n        @assert isconcretetype(T) # ... but check anyway\n        z = zero(T)\n        fill!(similar(x, typeof(z)), z)\n    end\nend\n\none(x::AbstractQuantity) = one(x.val)\none(x::AffineQuantity) =\n    throw(AffineError(\"no multiplicative identity for affine quantity $x.\"))\noneunit(x::AffineQuantity) = Quantity(one(x.val), absoluteunit(x))\noneunit(x::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U<:AffineUnits} = Quantity(one(T), absoluteunit(U()))\nget_T(::Type{<:AbstractQuantity{T}}) where T = T\nget_T(::Type{<:AbstractQuantity{T,D}}) where {T,D} = T\nget_T(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U} = T\none(x::Type{<:AbstractQuantity}) = one(get_T(x))\none(x::Type{<:AffineQuantity}) =\n    throw(AffineError(\"no multiplicative identity for affine quantity type $x.\"))\n\nisreal(x::AbstractQuantity) = isreal(x.val)\nisfinite(x::AbstractQuantity) = isfinite(x.val)\nisinf(x::AbstractQuantity) = isinf(x.val)\nisnan(x::AbstractQuantity) = isnan(x.val)\n@static if VERSION ≥ v\"1.7.0-DEV.119\"\n    isunordered(x::AbstractQuantity) = isunordered(x.val)\nend\n\neps(x::T) where {T<:AbstractQuantity} = T(eps(x.val))\neps(x::Type{T}) where {T<:AbstractQuantity} = eps(Unitful.numtype(T))\n\nunsigned(x::AbstractQuantity) = Quantity(unsigned(x.val), unit(x))\n\nfor f in (:exp, :exp10, :exp2, :expm1, :log, :log10, :log1p, :log2)\n    @eval ($f)(x::DimensionlessQuantity) = ($f)(uconvert(NoUnits, x))\nend\n\nreal(x::AbstractQuantity) = Quantity(real(x.val), unit(x))\nimag(x::AbstractQuantity) = Quantity(imag(x.val), unit(x))\nconj(x::AbstractQuantity) = Quantity(conj(x.val), unit(x))\n\n@inline norm(x::AbstractQuantity, p::Real=2) = Quantity(norm(x.val, p), unit(x))\n\n\"\"\"\n    sign(x::AbstractQuantity)\nReturns the sign of `x`.\n\"\"\"\nsign(x::AbstractQuantity) = sign(x.val)\n\n\"\"\"\n    signbit(x::AbstractQuantity)\nReturns the sign bit of the underlying numeric value of `x`.\n\"\"\"\nsignbit(x::AbstractQuantity) = signbit(x.val)\n\nprevfloat(x::AbstractQuantity{T}, d::Integer) where {T <: AbstractFloat} = Quantity(prevfloat(x.val, d), unit(x))\nprevfloat(x::AbstractQuantity{T}) where {T <: AbstractFloat} = prevfloat(x, 1)\nnextfloat(x::AbstractQuantity{T}, d::Integer) where {T <: AbstractFloat} = Quantity(nextfloat(x.val, d), unit(x))\nnextfloat(x::AbstractQuantity{T}) where {T <: AbstractFloat} = nextfloat(x, 1)\n\nfunction frexp(x::AbstractQuantity{T}) where {T <: AbstractFloat}\n    a,b = frexp(x.val)\n    a*unit(x), b\nend\n\nfor f in (:float, :BigFloat, :Float64, :Float32, :Float16)\n    @eval begin\n    \"\"\"\n        $($f)(x::AbstractQuantity)\n    Convert the numeric backing type of `x` to a floating-point representation.\n    Returns a `Quantity` with the same units.\n    \"\"\"\n    (Base.$f)(x::AbstractQuantity) = Quantity($f(x.val), unit(x))\n    end\nend\n   \n\"\"\"\n    Integer(x::AbstractQuantity)\nConvert the numeric backing type of `x` to an integer representation.\nReturns a `Quantity` with the same units.\n\"\"\"\nInteger(x::AbstractQuantity) = Quantity(Integer(x.val), unit(x))\n\n\"\"\"\n    Rational(x::AbstractQuantity)\nConvert the numeric backing type of `x` to a rational number representation.\nReturns a `Quantity` with the same units.\n\"\"\"\nRational(x::AbstractQuantity) = Quantity(Rational(x.val), unit(x))\n\nbig(x::AbstractQuantity{T,D,U}) where {T,D,U} = Quantity{big(T),D,U}(big(x.val))\nbig(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U} = Quantity{big(T),D,U}\n\nBase.hastypemax(::Type{<:AbstractQuantity{T}}) where {T} = Base.hastypemax(T)\n\ntypemin(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U} = typemin(T)*U()\ntypemin(x::AbstractQuantity{T}) where {T} = typemin(T)*unit(x)\n\ntypemax(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U} = typemax(T)*U()\ntypemax(x::AbstractQuantity{T}) where {T} = typemax(T)*unit(x)\n\nBase.literal_pow(::typeof(^), x::AbstractQuantity, ::Val{v}) where {v} =\n    Quantity(Base.literal_pow(^, x.val, Val(v)),\n             Base.literal_pow(^, unit(x), Val(v)))\n\n# All of these are needed for ambiguity resolution\n^(x::AbstractQuantity, y::Integer) = Quantity((x.val)^y, unit(x)^y)\n@static if VERSION ≥ v\"1.8.0-DEV.501\"\n    Base.@constprop(:aggressive, ^(x::AbstractQuantity, y::Rational) = Quantity((x.val)^y, unit(x)^y))\nelse\n    ^(x::AbstractQuantity, y::Rational) = Quantity((x.val)^y, unit(x)^y)\nend\n^(x::AbstractQuantity, y::Real) = Quantity((x.val)^y, unit(x)^y)\n\nBase.rand(r::Random.AbstractRNG, ::Random.SamplerType{<:AbstractQuantity{T,D,U}}) where {T,D,U} =\n    rand(r, T) * U()\nBase.ones(Q::Type{<:AbstractQuantity}, dims::NTuple{N,Integer}) where {N} =\n    fill!(Array{Q,N}(undef, map(Base.to_dim, dims)), oneunit(Q))\nBase.ones(Q::Type{<:AbstractQuantity}, dims::Tuple{}) = fill!(Array{Q}(undef), oneunit(Q))\nBase.ones(a::AbstractArray, Q::Type{<:AbstractQuantity}) = fill!(similar(a,Q), oneunit(Q))\n"
  },
  {
    "path": "src/range.jl",
    "content": "const colon = Base.:(:)\n\nimport Base: ArithmeticRounds\nimport Base: OrderStyle, Ordered, ArithmeticStyle, ArithmeticWraps\nimport Base.Broadcast: DefaultArrayStyle, broadcasted\n\n*(y::Units, r::AbstractRange) = *(r,y)\n*(r::AbstractRange, y::Units, z::Units...) = *(r, *(y,z...))\n\n# start, stop, length\nBase._range(start::Quantity, ::Nothing, stop, len::Integer) =\n    _unitful_start_stop_length(start, stop, len)\nBase._range(start, ::Nothing, stop::Quantity, len::Integer) =\n    _unitful_start_stop_length(start, stop, len)\nBase._range(start::Quantity, ::Nothing, stop::Quantity, len::Integer) =\n    _unitful_start_stop_length(start, stop, len)\nfunction _unitful_start_stop_length(start, stop, len)\n    dimension(start) != dimension(stop) && throw(DimensionError(start, stop))\n    a, b = promote(start, stop)\n    Base._range(a, nothing, b, len)\nend\nBase._range(start::T, ::Nothing, stop::T, len::Integer) where {T<:Quantity} =\n    LinRange{T}(start, stop, len)\nBase._range(start::T, ::Nothing, stop::T, len::Integer) where {T<:Quantity{<:Integer}} =\n    Base._linspace(Float64, ustrip(start), ustrip(stop), len, 1)*unit(T)\nBase._range(start::T, ::Nothing, stop::T, len::Integer) where {T<:Quantity{<:Base.IEEEFloat}} =\n    Base._range(ustrip(start), nothing, ustrip(stop), len) * unit(T)\n\n# start, step, length\nBase._range(a::T, step::T, ::Nothing, len::Integer) where {T<:Quantity{<:Base.IEEEFloat}} =\n    Base._range(ustrip(a), ustrip(step), nothing, len) * unit(T)\nBase._range(a::T, step::T, ::Nothing, len::Integer) where {T<:Quantity{<:AbstractFloat}} =\n    StepRangeLen{typeof(step*len),typeof(a),typeof(step)}(a, step, len)\nBase._range(a::T, step::T, ::Nothing, len::Integer) where {T<:Quantity} =\n    @static if VERSION ≥ v\"1.8.0-DEV\"\n        Base.range_start_step_length(a, step, len)\n    else\n        Base._rangestyle(OrderStyle(a), ArithmeticStyle(a), a, step, len)\n    end\nBase._range(a::Quantity{<:Real}, step::Quantity{<:AbstractFloat}, ::Nothing, len::Integer) =\n    _unitful_start_step_length(float(a), step, len)\nBase._range(a::Quantity{<:AbstractFloat}, step::Quantity{<:Real}, ::Nothing, len::Integer) =\n    _unitful_start_step_length(a, float(step), len)\nBase._range(a::Quantity{<:AbstractFloat}, step::Quantity{<:AbstractFloat}, ::Nothing, len::Integer) =\n    _unitful_start_step_length(a, step, len)\nBase._range(a, step::Quantity, ::Nothing, len::Integer) =\n    _unitful_start_step_length(a, step, len)\nBase._range(a::Quantity, step, ::Nothing, len::Integer) =\n    _unitful_start_step_length(a, step, len)\nBase._range(a::Quantity, step::Quantity, ::Nothing, len::Integer) =\n    _unitful_start_step_length(a, step, len)\nfunction _unitful_start_step_length(start, step, len)\n    dimension(start) != dimension(step) && throw(DimensionError(start,step))\n    Base._range(promote(start, uconvert(unit(start), step))..., nothing, len)\nend\n\n# start, length (step defaults to 1)\nBase._range(a::Quantity, ::Nothing, ::Nothing, len::Integer) =\n    Base._range(a, one(a), nothing, len)\n\n# step, stop, length\n@static if VERSION ≥ v\"1.7\"\n    Base._range(::Nothing, step, stop::Quantity, len::Integer) =\n        _unitful_step_stop_length(step, stop, len)\n    Base._range(::Nothing, step::Quantity, stop, len::Integer) =\n        _unitful_step_stop_length(step, stop, len)\n    Base._range(::Nothing, step::Quantity, stop::Quantity, len::Integer) =\n        _unitful_step_stop_length(step, stop, len)\n    Base._range(::Nothing, step::Quantity, ::Nothing, len::Integer) =\n        Base.range_error(nothing, step, nothing, len)\n    function _unitful_step_stop_length(step, stop, len)\n        dimension(stop) != dimension(step) && throw(DimensionError(stop,step))\n        Base.range_step_stop_length(promote(uconvert(unit(stop), step), stop)..., len)\n    end\nend\n\n# stop, length (step defaults to 1)\n@static if VERSION ≥ v\"1.7\"\n    Base._range(::Nothing, ::Nothing, stop::Quantity, len::Integer) =\n        Base._range(nothing, one(stop), stop, len)\nend\n\n*(r::AbstractRange, y::Units) = range(first(r)*y, step=step(r)*y, length=length(r))\n\n# first promote start and stop, leaving step alone\ncolon(start::A, step, stop::C) where {A<:Real,C<:Quantity} = colonstartstop(start,step,stop)\ncolon(start::A, step, stop::C) where {A<:Quantity,C<:Real} = colonstartstop(start,step,stop)\ncolon(a::T, b::Quantity, c::T) where {T<:Real} = colon(promote(a,b,c)...)\ncolon(start::Quantity{<:Real}, step, stop::Quantity{<:Real}) =\n    colon(promote(start, step, stop)...)\n\n# promotes start and stop\nfunction colonstartstop(start::A, step, stop::C) where {A,C}\n    dimension(start) != dimension(stop) && throw(DimensionError(start, stop))\n    colon(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop))\nend\n\nfunction colon(start::A, step::B, stop::A) where A<:Quantity{<:Real} where B<:Quantity{<:Real}\n    dimension(start) != dimension(step) && throw(DimensionError(start, step))\n    colon(promote(start, step, stop)...)\nend\n\nOrderStyle(::Type{<:AbstractQuantity{T}}) where T = OrderStyle(T)\nArithmeticStyle(::Type{<:AbstractQuantity{T}}) where T = ArithmeticStyle(T)\n\ncolon(start::T, step::T, stop::T) where {T<:Quantity{<:Real}} =\n    _colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop)\n_colon(::Ordered, ::Any, start::T, step, stop::T) where {T} = StepRange(start, step, stop)\n_colon(::Ordered, ::ArithmeticRounds, start::T, step, stop::T) where {T} =\n    StepRangeLen(start, step, floor(Int, (stop-start)/step)+1)\n_colon(::Any, ::Any, start::T, step, stop::T) where {T} =\n    StepRangeLen(start, step, floor(Int, (stop-start)/step)+1)\n\n# Opt into TwicePrecision functionality\n*(x::Base.TwicePrecision, y::Units) = Base.TwicePrecision(x.hi*y, x.lo*y)\n*(x::Base.TwicePrecision, y::Quantity) = (x * ustrip(y)) * unit(y)\nuconvert(y, x::Base.TwicePrecision) = Base.TwicePrecision(uconvert(y, x.hi), uconvert(y, x.lo))\nustrip(x::Base.TwicePrecision) = Base.TwicePrecision(ustrip(x.hi), ustrip(x.lo))\n@inline upreferred(x::Base.TwicePrecision{T}) where T<:Number = x\n@inline upreferred(x::Base.TwicePrecision{T}) where T<:AbstractQuantity =\n    uconvert(upreferred(unit(x)), x)\n\ncolon(start::T, step::T, stop::T) where {T<:Quantity{<:Base.IEEEFloat}} =\n    colon(ustrip(start), ustrip(step), ustrip(stop)) * unit(T) # This will always return a StepRangeLen\n\n# two-argument colon\ncolon(start, stop::Quantity) = _unitful_start_stop(start, stop)\ncolon(start::Quantity, stop) = _unitful_start_stop(start, stop)\ncolon(start::Quantity, stop::Quantity) = _unitful_start_stop(start, stop)\nfunction _unitful_start_stop(start, stop)\n    dimension(start) != dimension(stop) && throw(DimensionError(start, stop))\n    colon(promote(start, stop)...)\nend\nfunction colon(start::T, stop::T) where {T<:Quantity}\n    step = uconvert(unit(start), one(start))\n    colon(promote(start, step, stop)...)\nend\n\n# No need to confuse things by changing the type once units are on there,\n# if we can help it.\n*(r::StepRangeLen, y::Units) =\n    StepRangeLen{typeof(zero(eltype(r))*y)}(r.ref*y, r.step*y, length(r), r.offset)\n*(r::LinRange, y::Units) = LinRange(r.start*y, r.stop*y, length(r))\n*(r::StepRange, y::Units) = StepRange(r.start*y, r.step*y, r.stop*y)\n*(r::AbstractUnitRange, y::Units) = StepRange(first(r)*y, oneunit(first(r))*y, last(r)*y)\nfunction /(x::Base.TwicePrecision, v::Quantity)\n    x / Base.TwicePrecision(oftype(ustrip(x.hi)/ustrip(v)*unit(v), v))\nend\n\n# These can be removed (I think) if `range_start_step_length()` returns a `StepRangeLen` for\n# non-floats, cf. https://github.com/JuliaLang/julia/issues/40672\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::AbstractRange, x::AbstractQuantity) =\n    broadcasted(DefaultArrayStyle{1}(), *, r, ustrip(x)) * unit(x)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::AbstractQuantity, r::AbstractRange) =\n    broadcasted(DefaultArrayStyle{1}(), *, ustrip(x), r) * unit(x)\n\nconst BCAST_PROPAGATE_CALLS = Union{typeof(upreferred), Units}\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::AbstractRange, x::Ref{<:Units}) = r * x[]\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Ref{<:Units}, r::AbstractRange) = x[] * r\nbroadcasted(::DefaultArrayStyle{1}, x::BCAST_PROPAGATE_CALLS, r::StepRangeLen) = StepRangeLen{typeof(x(zero(eltype(r))))}(x(r.ref), x(r.step), r.len, r.offset)\nfunction broadcasted(::DefaultArrayStyle{1}, x::BCAST_PROPAGATE_CALLS, r::StepRange)\n    start = x(r.start)\n    au_to = absoluteunit(unit(start))\n    step = uconvert(au_to, r.step)\n    if Base.ArithmeticStyle(start) == Base.ArithmeticRounds() || Base.ArithmeticStyle(step) == Base.ArithmeticRounds()\n        au_from = absoluteunit(unit(r.start))\n        astart = ustrip(au_from, r.start)\n        astop = ustrip(au_from, r.stop)\n        len = length(r)\n        offset = _offset_for_steprangelen(astart, astop, len)\n        nb = ndigits(max(offset-1, len-offset), base=2, pad=0)\n        T = promote_type(typeof(start/unit(start)), typeof(step/unit(step)))\n        unitless_range = Base.steprangelen_hp(T, ustrip(au_to, r[offset]), ustrip(au_to, step), nb, len, offset)\n        return unitless_range * unit(start)\n    else\n        return StepRange(start, step, x(r.stop))\n    end\nend\nbroadcasted(::DefaultArrayStyle{1}, x::BCAST_PROPAGATE_CALLS, r::LinRange) = LinRange(x(r.start), x(r.stop), r.len)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(|>), r::AbstractRange, x::Ref{<:BCAST_PROPAGATE_CALLS}) = broadcasted(DefaultArrayStyle{1}(), x[], r)\n\nfunction _offset_for_steprangelen(start, stop, len)\n    if iszero(start)\n        return oneunit(len)\n    elseif iszero(stop)\n        return len\n    elseif signbit(start) == signbit(stop)\n        return abs(start) < abs(stop) ? oneunit(len) : len\n    else\n        fstart = Float64(start)\n        fstop = Float64(stop)\n        return round(typeof(len), (fstop-len*fstart)/(fstop-fstart))\n    end\nend\n\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(ustrip), r::StepRangeLen) =\n    StepRangeLen{typeof(ustrip(zero(eltype(r))))}(ustrip(unit(eltype(r)), r.ref), ustrip(unit(eltype(r)), r.step), r.len, r.offset)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(ustrip), r::StepRange) =\n    ustrip(unit(eltype(r)), r.start):ustrip(unit(eltype(r)), r.step):ustrip(unit(eltype(r)), r.stop)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(ustrip), r::LinRange) =\n    LinRange(ustrip(unit(eltype(r)), r.start), ustrip(unit(eltype(r)), r.stop), r.len)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(|>), r::AbstractRange, ::Ref{typeof(ustrip)}) =\n    broadcasted(DefaultArrayStyle{1}(), ustrip, r)\n\n# for ambiguity resolution\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::StepRangeLen{T}, x::AbstractQuantity) where T =\n    broadcasted(DefaultArrayStyle{1}(), *, r, ustrip(x)) * unit(x)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::AbstractQuantity, r::StepRangeLen{T}) where T =\n    broadcasted(DefaultArrayStyle{1}(), *, ustrip(x), r) * unit(x)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::LinRange, x::AbstractQuantity) =\n    LinRange(r.start*x, r.stop*x, r.len)\nbroadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::AbstractQuantity, r::LinRange) =\n    LinRange(x*r.start, x*r.stop, r.len)\n"
  },
  {
    "path": "src/types.jl",
    "content": "\n\"\"\"\n    abstract type Unitlike end\nRepresents units or dimensions. Dimensions are unit-like in the sense that they are\nnot numbers but you can multiply or divide them and exponentiate by rationals.\n\"\"\"\nabstract type Unitlike end\n\n\"\"\"\n    struct Dimension{D}\n        power::Rational{Int}\n    end\nDescription of a dimension. The name of the dimension `D` is a symbol, e.g.\n`:Length`, `:Time`, `:Mass`, etc.\n\n`Dimension{D}` objects are collected in a tuple, which is used for the type\nparameter `N` of a [`Dimensions{N}`](@ref) object.\n\"\"\"\nstruct Dimension{D}\n    power::Rational{Int}\nend\n@inline name(x::Dimension{D}) where {D} = D\n@inline power(x::Dimension) = x.power\n\n\"\"\"\n    struct Dimensions{N} <: Unitlike\nInstances of this object represent dimensions, possibly combinations thereof.\n\"\"\"\nstruct Dimensions{N} <: Unitlike end\n\"    Unitful.NoDims\n\\nA dimension representing quantities without dimensions.\"\nconst NoDims = Dimensions{()}()\n\n\"\"\"\n    struct Unit{U,D}\n        tens::Int\n        power::Rational{Int}\n    end\nDescription of a physical unit, including powers-of-ten prefixes and powers of\nthe unit. The name of the unit is encoded in the type parameter `U` as a symbol,\ne.g. `:Meter`, `:Second`, `:Gram`, etc. The type parameter `D` is a [`Dimensions{N}`](@ref)\nobject, for instance `Unit{:Meter, 𝐋}` or `Unit{:Liter, 𝐋^3}`. Note that the dimension\ninformation refers to the unit, not powers of the unit.\n\n`Unit{U,D}` objects are almost never explicitly manipulated by the user. They\nare collected in a tuple, which is used for the type parameter `N` of a\n[`Units{N,D,A}`](@ref) object.\n\"\"\"\nstruct Unit{U,D}\n    tens::Int\n    power::Rational{Int}\nend\n@inline name(x::Unit{U}) where {U} = U\n@inline tens(x::Unit) = x.tens\n@inline power(x::Unit) = x.power\n\n\"\"\"\n    dimension(x::Unit)\nReturns a [`Unitful.Dimensions`](@ref) object describing the given unit `x`.\n\"\"\"\n@inline dimension(u::Unit{U,D}) where {U,D} = D^u.power\n\nstruct Affine{T} end\n\n\"\"\"\n    abstract type Units{N,D,A} <: Unitlike end\nAbstract supertype of all units objects, which can differ in their implementation details.\n`A` is a translation for affine quantities; for non-affine quantities it is `nothing`.\n\"\"\"\nabstract type Units{N,D,A} <: Unitlike end\n\naffinetranslation(::Units{N,D,Affine{T}}) where {N,D,T} = T\naffinetranslation(::Units{N,D,nothing}) where {N,D} = false\n\n\"\"\"\n    genericunit(::Units)\nGiven e.g. a `FreeUnits{N,D,A}`, `ContextUnits{N,D,P,A}`, or `FixedUnits{N,D,A}` object,\nreturn the type `Units{N,D,A}`.\n\"\"\"\ngenericunit(::Units{N,D,A}) where {N,D,A} = Units{N,D,A}\n\n\"\"\"\n    struct FreeUnits{N,D,A} <: Units{N,D,A}\nInstances of this object represent units, possibly combinations thereof. These behave like\nunits have behaved in previous versions of Unitful, and provide a basic level of\nfunctionality that should be acceptable to most users. See\n[Basic promotion mechanisms](@ref) in the docs for details.\n\nExample: the unit `m` is actually a singleton of type\n`Unitful.FreeUnits{(Unitful.Unit{:Meter, 𝐋}(0, 1//1),), 𝐋, nothing}`.\nAfter dividing by `s`, a singleton of type\n`Unitful.FreeUnits{(Unitful.Unit{:Meter, 𝐋}(0, 1//1), Unitful.Unit{:Second, 𝐓}(0, -1//1)), 𝐋/𝐓, nothing}` is returned.\n\"\"\"\nstruct FreeUnits{N,D,A} <: Units{N,D,A} end\nFreeUnits{N,D}() where {N,D} = FreeUnits{N,D,nothing}()\nFreeUnits(::Units{N,D,A}) where {N,D,A} = FreeUnits{N,D,A}()\n\n\"\"\"\n    NoUnits\nAn object that represents \"no units\", i.e., the units of a unitless number. The type of\nthe object is `Unitful.FreeUnits{(), NoDims}`. It is displayed as an empty string.\n\nExample:\n```jldoctest\njulia> unit(1.0) == NoUnits\ntrue\n```\n\"\"\"\nconst NoUnits = FreeUnits{(), NoDims}()\n(y::FreeUnits)(x) = uconvert(y,x)\n\n\"\"\"\n    struct ContextUnits{N,D,P,A} <: Units{N,D,A}\nInstances of this object represent units, possibly combinations thereof.\nIt is in most respects like `FreeUnits{N,D,A}`, except that the type parameter `P` is\nagain a `FreeUnits{M,D}` type that specifies a preferred unit for promotion.\nSee [Advanced promotion mechanisms](@ref) in the docs for details.\n\"\"\"\nstruct ContextUnits{N,D,P,A} <: Units{N,D,A} end\nfunction ContextUnits(x::Units{N,D,A}, y::Units) where {N,D,A}\n    D !== dimension(y) && throw(DimensionError(x,y))\n    ContextUnits{N,D,typeof(FreeUnits(y)),A}()\nend\nContextUnits{N,D,P}() where {N,D,P} = ContextUnits{N,D,P,nothing}()\nContextUnits(u::Units{N,D,A}) where {N,D,A} =\n    ContextUnits{N,D,typeof(FreeUnits(upreferred(u))),A}()\n(y::ContextUnits)(x) = uconvert(y,x)\n\n\"\"\"\n    struct FixedUnits{N,D,A} <: Units{N,D,A} end\nInstances of this object represent units, possibly combinations thereof.\nThese are primarily intended for use when you would like to disable automatic unit\nconversions. See [Advanced promotion mechanisms](@ref) in the docs for details.\n\"\"\"\nstruct FixedUnits{N,D,A} <: Units{N,D,A} end\nFixedUnits{N,D}() where {N,D} = FixedUnits{N,D,nothing}()\nFixedUnits(::Units{N,D,A}) where {N,D,A} = FixedUnits{N,D,A}()\n\n\n\"\"\"\n    abstract type AbstractQuantity{T,D,U} <: Number end\nRepresents a generic quantity type, whose dimensions and units are specified in\nthe type signature.  The dimensions and units are allowed to be the empty set,\nin which case a dimensionless, unitless number results.\n\nThe type parameter `T` represents the numeric backing type. The type parameters\n`D :: ` [`Unitful.Dimensions`](@ref) and `U <: ` [`Unitful.Units`](@ref).\nOf course, the dimensions follow from the units, but the type parameters are\nkept separate to permit convenient dispatch on dimensions.\n\"\"\"\nabstract type AbstractQuantity{T,D,U} <: Number end\n\n\"\"\"\n    struct Quantity{T,D,U} <: AbstractQuantity{T,D,U}\nA concrete subtype of [`Unitful.AbstractQuantity`](@ref).\n\nThe type parameter `T` represents the numeric backing type. The type parameters\n`D :: ` [`Unitful.Dimensions`](@ref) and `U <: ` [`Unitful.Units`](@ref).\n\"\"\"\nstruct Quantity{T,D,U} <: AbstractQuantity{T,D,U}\n    val::T\n    Quantity{T,D,U}(v::Number) where {T,D,U} = new{T,D,U}(v)\n    Quantity{T,D,U}(v::Quantity) where {T,D,U} = convert(Quantity{T,D,U}, v)\nend\n\n# Field-only constructor\nQuantity{<:Any,D,U}(val::Number) where {D,U} = Quantity{typeof(val),D,U}(val)\n\n\"\"\"\n    DimensionlessUnits{U}\nUseful for dispatching on [`Unitful.Units`](@ref) types that have no dimensions.\n\nExample:\n```jldoctest\njulia> isa(Unitful.rad, DimensionlessUnits)\ntrue\n\"\"\"\nconst DimensionlessUnits{U} = Units{U, NoDims}\n\n\"\"\"\n    AffineUnits{N,D,A} = Units{N,D,A} where A<:Affine\nUseful for dispatching on unit objects that indicate a quantity should affine-transform\nunder unit conversion, like absolute temperatures. Not exported.\n\"\"\"\nconst AffineUnits{N,D,A} = Units{N,D,A} where A<:Affine\n\n\"\"\"\n    ScalarUnits{N,D} = Units{N,D,nothing}\nUseful for dispatching on unit objects that indicate a quantity should transform in the\nusual scalar way under unit conversion. Not exported.\n\"\"\"\nconst ScalarUnits{N,D} = Units{N,D,nothing}\n\n\"\"\"\n    DimensionlessQuantity{T,U} = AbstractQuantity{T, NoDims, U}\nUseful for dispatching on [`Unitful.Quantity`](@ref) types that may have units\nbut no dimensions. (Units with differing power-of-ten prefixes are not canceled\nout.)\n\nExample:\n```jldoctest\njulia> isa(1.0u\"mV/V\", DimensionlessQuantity)\ntrue\n```\n\"\"\"\nconst DimensionlessQuantity{T,U} = AbstractQuantity{T, NoDims, U}\n\n\"\"\"\n    AffineQuantity{T,D,U} = AbstractQuantity{T,D,U} where U<:AffineUnits\nUseful for dispatching on quantities that affine-transform under unit conversion, like\nabsolute temperatures. Not exported.\n\"\"\"\nconst AffineQuantity{T,D,U} = AbstractQuantity{T,D,U} where U<:AffineUnits\n\n\"\"\"\n    ScalarQuantity{T,D,U} = AbstractQuantity{T,D,U} where U<:ScalarUnits\nUseful for dispatching on quantities that transform in the usual scalar way under unit\nconversion. Not exported.\n\"\"\"\nconst ScalarQuantity{T,D,U} = AbstractQuantity{T,D,U} where U<:ScalarUnits\n\n\"\"\"\n    struct LogInfo{N,B,P}\nDescribes a logarithmic unit. Type parameters include:\n- `N`: The name of the logarithmic unit, e.g. `:Decibel`, `:Neper`.\n- `B`: The base of the logarithm.\n- `P`: A prefactor to multiply the logarithm when the log is of a power ratio.\n\"\"\"\nstruct LogInfo{N,B,P} end\n\n\"\"\"\n    abstract type LogScaled{L<:LogInfo} <: Number end\nAbstract supertype of [`Unitful.Level`](@ref) and [`Unitful.Gain`](@ref). It is only\nused in promotion to put levels and gains onto a common log scale.\n\"\"\"\nabstract type LogScaled{L<:LogInfo} <: Number end\n\nconst RealOrRealQuantity = Union{Real, AbstractQuantity{<:Real}}\n\n\"\"\"\n    struct Level{L, S, T<:Union{Real, AbstractQuantity{<:Real}}} <: LogScaled{L}\nA logarithmic scale-based level. Details about the logarithmic scale are encoded in\n`L <: LogInfo`. `S` is a reference quantity for the level, not a type. This type has one\nfield, `val::T`, and the log of the ratio `val/S` is taken. This type differs from\n[`Unitful.Gain`](@ref) in that `val` is a linear quantity.\n\"\"\"\nstruct Level{L, S, T<:RealOrRealQuantity} <: LogScaled{L}\n    val::T\n    function Level{L,S,T}(x::Number) where {L,S,T}\n        S isa ReferenceQuantity || throw(DomainError(S, \"Reference quantity must be real.\"))\n        dimension(S) != dimension(x) && throw(DimensionError(S,x))\n        return new{L,S,T}(x)\n    end\nend\nLevel{L,S}(val::Number) where {L,S} = Level{L,S,real(typeof(val))}(val)\nLevel{L,S}(val::RealOrRealQuantity) where {L,S} = Level{L,S,typeof(val)}(val)\n\n\"\"\"\n    struct Gain{L, S, T<:Real} <: LogScaled{L}\nA logarithmic scale-based gain or attenuation factor. This type has one field, `val::T`.\nFor example, given a gain of `20dB`, we have `val===20`. This type differs from\n[`Unitful.Level`](@ref) in that `val` is stored after computing the logarithm.\n\"\"\"\nstruct Gain{L, S, T<:Real} <: LogScaled{L}\n    val::T\n    Gain{L, S, T}(x::Number) where {L,S,T<:Real} = new{L,S,T}(x)\nend\n\n\"\"\"\n    struct MixedUnits{T<:LogScaled, U<:Units}\n\nStruct for representing mixed logarithmic / linear units. Primarily useful as an\nintermediate for `uconvert`. `T` is `<: Level` or `<: Gain`.\n\"\"\"\nstruct MixedUnits{T<:LogScaled, U<:Units}\n    units::U\nend\nMixedUnits{T}() where {T} = MixedUnits{T, typeof(NoUnits)}(NoUnits)\nMixedUnits{T}(u::Units) where {T} = MixedUnits{T,typeof(u)}(u)\n(y::MixedUnits)(x) = uconvert(y,x)\n\n# For logarithmic quantities\nstruct IsRootPowerRatio{S,T}\n    val::T\nend\nIsRootPowerRatio{S}(x) where {S} = IsRootPowerRatio{S, typeof(x)}(x)\nBase.show(io::IO, x::IsRootPowerRatio{S}) where {S} =\n    print(io, ifelse(S, \"root-power ratio\", \"power ratio\"), \" with reference \", x.val)\nconst PowerRatio{T} = IsRootPowerRatio{false,T}\nconst RootPowerRatio{T} = IsRootPowerRatio{true,T}\n@inline unwrap(x::IsRootPowerRatio) = x.val\n@inline unwrap(x) = x\n\nconst ReferenceQuantity =\n    Union{RealOrRealQuantity, IsRootPowerRatio{S, <:RealOrRealQuantity} where S}\n\n\"\"\"\n    reflevel(x::Level{L,S})\n    reflevel(::Type{Level{L,S}})\n    reflevel(::Type{Level{L,S,T}})\nReturns the reference level, e.g.\n\n```jldoctest\njulia> reflevel(3u\"dBm\")\n1 mW\n```\n\"\"\"\nfunction reflevel end\n@inline reflevel(x::Level{L,S}) where {L,S} = unwrap(S)\n@inline reflevel(::Type{Level{L,S}}) where {L,S} = unwrap(S)\n@inline reflevel(::Type{Level{L,S,T}}) where {L,S,T} = unwrap(S)\n"
  },
  {
    "path": "src/units.jl",
    "content": "@generated function *(a0::FreeUnits, a::FreeUnits...)\n\n    # Sort the units uniquely. This is a generated function so that we\n    # don't have to figure out the units each time.\n    linunits = Vector{Unit}()\n\n    nunits = length(a) + 1\n    for x in (a0, a...)\n        (x.parameters[3] !== nothing) && (nunits > 1) &&\n            throw(AffineError(\"an invalid operation was attempted with affine units: $(x())\"))\n        xp = x.parameters[1]\n        append!(linunits, xp[1:end])\n    end\n\n    # linunits is an Array containing all of the Unit objects that were\n    # found in the type parameters of the FreeUnits objects (a0, a...)\n    sort!(linunits, by=power)\n    sort!(linunits, by=tens)\n    sort!(linunits, by=name)\n\n    # [m,m,cm,cm^2,cm^3,nm,m^4,μs,μs^2,s]\n    # reordered as:\n    # [nm,cm,cm^2,cm^3,m,m,m^4,μs,μs^2,s]\n\n    # Collect powers of a given unit into `c`\n    c = Vector{Unit}()\n    if !isempty(linunits)\n        next = iterate(linunits)\n        p = 0//1\n        oldvalue = next[1]\n        while next !== nothing\n            (value, state) = next\n            if tens(value) == tens(oldvalue) && name(value) == name(oldvalue)\n                p += power(value)\n            else\n                if p != 0\n                    push!(c, Unit{name(oldvalue), dimtype(oldvalue)}(tens(oldvalue), p))\n                end\n                p = power(value)\n            end\n            oldvalue = value\n            next = iterate(linunits, state)\n        end\n        if p != 0\n            push!(c, Unit{name(oldvalue), dimtype(oldvalue)}(tens(oldvalue), p))\n        end\n    end\n    # results in:\n    # [nm,cm^6,m^6,μs^3,s]\n\n    d = (c...,)\n    f = mapreduce(dimension, *, d; init=NoDims)\n    :(FreeUnits{$d,$f,$(a0.parameters[3])}())\nend\n*(a0::ContextUnits, a::ContextUnits...) =\n    ContextUnits(*(FreeUnits(a0), FreeUnits.(a)...),\n                    *(FreeUnits(upreferred(a0)), FreeUnits.((upreferred).(a))...))\nFreeOrContextUnits = Union{FreeUnits, ContextUnits}\n*(a0::FreeOrContextUnits, a::FreeOrContextUnits...) =\n    *(ContextUnits(a0), ContextUnits.(a)...)\n*(a0::FixedUnits, a::FixedUnits...) =\n    FixedUnits(*(FreeUnits(a0), FreeUnits.(a)...))\n\n\"\"\"\n```\n*(a0::Units, a::Units...)\n```\n\nGiven however many units, multiply them together. This is actually handled by\na few different methods, since we have `FreeUnits`, `ContextUnits`, and `FixedUnits`.\n\nCollect [`Unitful.Unit`](@ref) objects from the type parameter of the\n[`Unitful.Units`](@ref) objects. For identical units including SI prefixes\n(i.e. `cm` ≠ `m`), collect powers and sort uniquely by the name of the `Unit`.\nThe unique sorting permits easy unit comparisons.\n\nExamples:\n\n```jldoctest\njulia> u\"kg*m/s^2\"\nkg m s^-2\n\njulia> u\"m/s*kg/s\"\nkg m s^-2\n\njulia> typeof(u\"m/s*kg/s\") == typeof(u\"kg*m/s^2\")\ntrue\n```\n\"\"\"\n*(a0::Units, a::Units...) = FixedUnits(*(FreeUnits(a0), FreeUnits.(a)...))\n# Logic above is that if we're not using FreeOrContextUnits, at least one is FixedUnits.\n\n*(a0::Units, a::Missing) = missing\n*(a0::Missing, a::Units) = missing\n*(a0::MixedUnits, a::Missing) = missing\n*(a0::Missing, a::MixedUnits) = missing\n\n/(x::Units, y::Units) = *(x,inv(y))\n\n/(x::Units, y::Missing) = missing\n/(x::Missing, y::Units) = missing\n/(x::MixedUnits, y::Missing) = missing\n/(x::Missing, y::MixedUnits) = missing\n\n//(x::Units, y::Units)  = x/y\n\n# Both methods needed for ambiguity resolution\n^(x::Unit{U,D}, y::Integer) where {U,D} = Unit{U,D}(tens(x), power(x)*y)\n^(x::Unit{U,D}, y::Number) where {U,D} = Unit{U,D}(tens(x), power(x)*y)\n\n# A word of caution:\n# Exponentiation is not type-stable for `Units` objects.\n# Dimensions get reconstructed anyway so we pass () for the D type parameter...\n^(x::AffineUnits, y::Integer) =\n    throw(AffineError(\"an invalid operation was attempted with affine units: $x\"))\n^(x::AffineUnits, y::Number) =\n    throw(AffineError(\"an invalid operation was attempted with affine units: $x\"))\n\n^(x::FreeUnits{N,D,nothing}, y::Integer) where {N,D} = *(FreeUnits{map(a->a^y, N), ()}())\n^(x::FreeUnits{N,D,nothing}, y::Number) where {N,D} = *(FreeUnits{map(a->a^y, N), ()}())\n\n^(x::ContextUnits{N,D,P,nothing}, y::Integer) where {N,D,P} =\n    *(ContextUnits{map(a->a^y, N), (), typeof(P()^y)}())\n^(x::ContextUnits{N,D,P,nothing}, y::Number) where {N,D,P} =\n    *(ContextUnits{map(a->a^y, N), (), typeof(P()^y)}())\n\n^(x::FixedUnits{N,D,nothing}, y::Integer) where {N,D} = *(FixedUnits{map(a->a^y, N), ()}())\n^(x::FixedUnits{N,D,nothing}, y::Number) where {N,D} = *(FixedUnits{map(a->a^y, N), ()}())\n\n^(x::Units, y::Missing) = missing\n^(x::Missing, y::Units) = missing\n\nBase.literal_pow(::typeof(^), x::AffineUnits, ::Val{p}) where p =\n    throw(AffineError(\"an invalid operation was attempted with affine units: $x\"))\n\n@generated function Base.literal_pow(::typeof(^), x::FreeUnits{N,D,nothing}, ::Val{p}) where {N,D,p}\n    y = *(FreeUnits{map(a->a^p, N), ()}())\n    :($y)\nend\n@generated function Base.literal_pow(::typeof(^), x::ContextUnits{N,D,P,nothing}, ::Val{p}) where {N,D,P,p}\n    y = *(ContextUnits{map(a->a^p, N), (), typeof(P()^p)}())\n    :($y)\nend\n@generated function Base.literal_pow(::typeof(^), x::FixedUnits{N,D,nothing}, ::Val{p}) where {N,D,p}\n    y = *(FixedUnits{map(a->a^p, N), ()}())\n    :($y)\nend\n\n# Since exponentiation is not type stable, we define a special `inv` method to enable fast\n# division. For julia 0.6.0, the appropriate methods for ^ and * need to be defined before\n# this one!\nfor (fun,pow) in ((:inv, -1//1), (:sqrt, 1//2), (:cbrt, 1//3))\n    # The following are generated functions to ensure type stability.\n    @eval @generated function ($fun)(x::FreeUnits)\n        (x <: AffineUnits) && throw(\n            AffineError(\"an invalid operation was attempted with affine units: $(x())\"))\n        unittuple = map(x->x^($pow), x.parameters[1])\n        y = *(FreeUnits{unittuple,()}())    # sort appropriately\n        :($y)\n    end\n\n    @eval @generated function ($fun)(x::ContextUnits)\n        (x <: AffineUnits) && throw(\n            AffineError(\"an invalid operation was attempted with affine units: $(x())\"))\n        unittuple = map(x->x^($pow), x.parameters[1])\n        promounit = ($fun)(x.parameters[3]())\n        y = *(ContextUnits{unittuple,(),typeof(promounit)}())   # sort appropriately\n        :($y)\n    end\n\n    @eval @generated function ($fun)(x::FixedUnits)\n        (x <: AffineUnits) && throw(\n            AffineError(\"an invalid operation was attempted with affine units: $(x())\"))\n        unittuple = map(x->x^($pow), x.parameters[1])\n        y = *(FixedUnits{unittuple,()}())   # sort appropriately\n        :($y)\n    end\nend\n\nfunction tensfactor(x::Unit)\n    p = power(x)\n    if isinteger(p)\n        p = Integer(p)\n    end\n    tens(x)*p\nend\n\n@generated function tensfactor(x::Units)\n    tunits = x.parameters[1]\n    a = mapreduce(tensfactor, +, tunits; init=0)\n    :($a)\nend\n\n# This is type unstable but\n# a) this method is not called by the user\n# b) ultimately the instability will only be present at compile time as it is\n# hidden behind a \"generated function barrier\"\nfunction basefactor(inex, ex, eq, tens, p)\n    # Sometimes (x::Rational)^1 can fail for large rationals because the result\n    # is of type x*x so we do a hack here\n    function dpow(x, p)\n        if p == 0\n            1\n        elseif p == 1\n            x\n        elseif p == -1\n            1//x\n        else\n            x^p\n        end\n    end\n\n    if isinteger(p)\n        p = Integer(p)\n    end\n    if isinteger(tens)\n        tens = Integer(tens)\n    end\n\n    eq_is_exact = false\n    output_ex_float = (10.0^tens * float(ex))^p\n    eq_raised = float(eq)^p\n    if isa(eq, Integer) || isa(eq, Rational)\n        output_ex_float *= eq_raised\n        eq_is_exact = true\n    end\n\n    can_exact = (output_ex_float < typemax(Int))\n    can_exact &= (1/output_ex_float < typemax(Int))\n    can_exact &= isinteger(p)\n\n    can_exact2 = (eq_raised < typemax(Int))\n    can_exact2 &= (1/eq_raised < typemax(Int))\n    can_exact2 &= isinteger(p)\n\n    if can_exact && isinteger(tens)\n        if eq_is_exact\n            # If we got here then p is an integer.\n            # Note that sometimes x^1 can cause an overflow error if x is large because\n            # of how power_by_squaring is implemented for Rationals, so we use dpow.\n            x = dpow(eq*ex*(10//1)^tens, p)\n            result = (inex^p, isinteger(x) ? Int(x) : x)\n        else\n            x = dpow(ex*(10//1)^tens, p)\n            result = ((inex * eq)^p, isinteger(x) ? Int(x) : x)\n        end\n    else\n        if eq_is_exact && can_exact2\n            x = dpow(eq, p)\n            result = ((inex * ex * 10.0^tens)^p, isinteger(x) ? Int(x) : x)\n        else\n            result = ((inex * ex * 10.0^tens * eq)^p, 1)\n        end\n    end\n    if fp_overflow_underflow(inex, first(result))\n        throw(ArgumentError(\"Floating point overflow/underflow, probably due to large exponent ($p)\"))\n    end\n    return result\nend\n\n\"\"\"\n    basefactor(x::Unit)\nSpecifies conversion factors to reference units.\nIt returns a tuple. The first value is any irrational part of the conversion,\nand the second value is a rational component. This segregation permits exact\nconversions within unit systems that have no rational conversion to the\nreference units.\n\"\"\"\n@inline basefactor(x::Unit{U}) where {U} = basefactor(basefactors[U]..., 1, 0, power(x))\n\nfunction basefactor(::Units{U}) where {U}\n    fact1 = map(basefactor, U)\n    inex1 = mapreduce(first, *, fact1, init=1.0)\n    float_num = mapreduce(x -> float(numerator(last(x))), *, fact1, init=1.0)\n    float_den = mapreduce(x -> float(denominator(last(x))), *, fact1, init=1.0)\n    can_exact = float_num < typemax(Int) && float_den < typemax(Int)\n    if can_exact\n        result = (inex1, mapreduce(last, *, fact1, init=1))\n    else\n        result = (inex1 * (float_num / float_den), 1)\n    end\n    if any(fp_overflow_underflow(first(x), first(result)) for x in fact1)\n        throw(ArgumentError(\"Floating point overflow/underflow, probably due to a large exponent in some of the units\"))\n    end\n    return result\nend\n\nBase.broadcastable(x::Units) = Ref(x)\n\nBase.nbitslen(::Type{Q}, len, offset) where Q<:Quantity =\n    Base.nbitslen(numtype(Q), len, offset)\n\nustrip(x::Base.TwicePrecision{Q}) where Q<:Quantity =\n    Base.TwicePrecision(ustrip(x.hi), ustrip(x.lo))\nunit(x::Base.TwicePrecision{Q}) where Q<:Quantity = unit(x.hi)\n\nfunction Base.twiceprecision(x::Union{Q,Base.TwicePrecision{Q}}, nb::Integer) where Q<:Quantity\n    xt = Base.twiceprecision(ustrip(x), nb)\n    return Base.TwicePrecision(xt.hi*unit(x), xt.lo*unit(x))\nend\n\nfunction *(x::Base.TwicePrecision{Q}, v::Real) where Q<:Quantity\n    v == 0 && return Base.TwicePrecision(x.hi*v, x.lo*v)\n    (ustrip(x) * Base.TwicePrecision(oftype(ustrip(x.hi)*v, v))) * unit(x)\nend\n\nBase.mul12(x::Quantity, y::Quantity) = Base.mul12(ustrip(x), ustrip(y)) .* (unit(x) * unit(y))\nBase.mul12(x::Quantity, y::Real)     = Base.mul12(ustrip(x), y) .* unit(x)\nBase.mul12(x::Real, y::Quantity)     = Base.mul12(x, ustrip(y)) .* unit(y)\n\n# The following method must not be defined before `*(a0::FreeUnits, a::FreeUnits...)`\n\"\"\"\n    upreferred(x::Dimensions)\nReturn units which are preferred for dimensions `x`. If you are using the\nfactory defaults, this function will return a product of powers of base SI units\n(as [`Unitful.FreeUnits`](@ref)).\n\"\"\"\n@generated function upreferred(x::Dimensions{D}) where {D}\n    u = prod((NoUnits, (promotion[name(z)]^z.power for z in D)...))\n    :($u)\nend\n"
  },
  {
    "path": "src/user.jl",
    "content": "\"\"\"\n    register(unit_module::Module)\nMakes Unitful aware of units defined in a new unit module, including making the\n[`@u_str`](@ref) macro work with these units. By default, Unitful is itself a\nregistered module. Note that Main is not, so if you define new units at the\nREPL, you will probably want to do `Unitful.register(Main)`.\n\nExample:\n```julia\n# somewhere in a custom units package...\nmodule MyUnitsPackage\nusing Unitful\n\nfunction __init__()\n    ...\n    Unitful.register(MyUnitsPackage)\nend\nend #module\n```\n\"\"\"\nfunction register(unit_module::Module)\n    push!(Unitful.unitmodules, unit_module)\n    if unit_module !== Unitful\n        merge!(Unitful.basefactors, _basefactors(unit_module))\n    end\nend\n\n\"\"\"\n    @dimension(symb, abbr, name, autodocs=false)\nCreates new dimensions. `name` will be used like an identifier in the type\nparameter for a [`Unitful.Dimension`](@ref) object. `symb` will be a symbol\ndefined in the namespace from which this macro is called that is bound to a\n[`Unitful.Dimensions`](@ref) object. For most intents and purposes it is this\nobject that the user would manipulate in doing dimensional analysis. The symbol\nis not exported.\n\nThis macro extends [`Unitful.abbr`](@ref) to display the new dimension in an\nabbreviated format using the string `abbr`.\n\nType aliases are created that allow the user to dispatch on\n[`Unitful.Quantity`](@ref), [`Unitful.Level`](@ref) and [`Unitful.Units`](@ref) objects\nof the newly defined dimension. The type alias for quantities or levels is simply given by\n`name`, and the type alias for units is given by `name*\"Units\"`, e.g. `LengthUnits`.\nNote that there is also `LengthFreeUnits`, for example, which is an alias for\ndispatching on `FreeUnits` with length dimensions. The aliases are not exported.\nIf `autodocs == true`, docstrings will be automatically generated for these aliases.\n\n!!! compat \"Unitful 1.10\"\n    Documenting the resulting dimension symbol by adding a docstring before the `@dimension`\n    call requires Unitful 1.10 or later. The `autodocs` argument also requires Unitful 1.10\n    or later.\n\nFinally, if you define new dimensions with [`@dimension`](@ref) you will need\nto specify a preferred unit for that dimension with [`Unitful.preferunits`](@ref),\notherwise promotion will not work with that dimension. This is done automatically\nin the [`@refunit`](@ref) macro.\n\nReturns the `Dimensions` object to which `symb` is bound.\n\nUsage example from `src/pkgdefaults.jl`: `@dimension 𝐋 \"𝐋\" Length`\n\"\"\"\nmacro dimension(symb, abbr, name, autodocs=false)\n    s = Symbol(symb)\n    x = Expr(:quote, name)\n    uname = Symbol(name,\"Units\")\n    funame = Symbol(name,\"FreeUnits\")\n    name_links = __module__ == Unitful ? \"[`Unitful.Quantity`](@ref), [`Unitful.Level`](@ref)\" : \"`Unitful.Quantity`, `Unitful.Level`\"\n    unit_links = __module__ == Unitful ? \"[`Unitful.Units`](@ref)\" : \"`Unitful.Units`\"\n    funit_links = __module__ == Unitful ? \"[`Unitful.FreeUnits`](@ref)\" : \"`Unitful.FreeUnits`\"\n    name_doc =  \"\"\"\n                    $__module__.$name{T, U}\n\n                A supertype for quantities and levels of dimension [`$__module__.$s`](@ref) with a value\n                of type `T` and units `U`.\n\n                See also: [`$__module__.$s`](@ref), $name_links.\n                \"\"\"\n    unit_doc =  \"\"\"\n                    $__module__.$uname{U}\n\n                A supertype for units of dimension [`$__module__.$s`](@ref). Equivalent to\n                `Unitful.Units{U, $__module__.$s}`.\n\n                See also: [`$__module__.$s`](@ref), $unit_links.\n                \"\"\"\n    funit_doc = \"\"\"\n                    $__module__.$funame{U}\n\n                A supertype for $funit_links of dimension [`$__module__.$s`](@ref). Equivalent to\n                `Unitful.FreeUnits{U, $__module__.$s}`.\n\n                See also: [`$__module__.$s`](@ref).\n                \"\"\"\n    esc(quote\n        $Unitful.abbr(::$Dimension{$x}) = $abbr\n        Base.@__doc__ const global $s = $Dimensions{($Dimension{$x}(1),)}()\n        const global ($name){T,U} = Union{\n            $Quantity{T,$s,U},\n            $Level{L,S,$Quantity{T,$s,U}} where {L,S}}\n        const global ($uname){U} = $Units{U,$s}\n        const global ($funame){U} = $FreeUnits{U,$s}\n        if $autodocs\n            @doc $name_doc $name\n            @doc $unit_doc $uname\n            @doc $funit_doc $funame\n        end\n        $s\n    end)\nend\n\n\"\"\"\n    @derived_dimension(name, dims, autodocs=false)\nCreates type aliases to allow dispatch on [`Unitful.Quantity`](@ref),\n[`Unitful.Level`](@ref), and [`Unitful.Units`](@ref) objects of a derived dimension,\nlike area, which is just length squared. The type aliases are not exported.\nIf `autodocs == true`, docstrings will be automatically generated for these aliases.\n\n!!! compat \"Unitful 1.10\"\n    The `autodocs` argument requires Unitful 1.10 or later.\n\n`dims` is a [`Unitful.Dimensions`](@ref) object.\n\nReturns `nothing`.\n\nUsage examples:\n\n- `@derived_dimension Area 𝐋^2` gives `Area` and `AreaUnit` type aliases\n- `@derived_dimension Speed 𝐋/𝐓` gives `Speed` and `SpeedUnit` type aliases\n\"\"\"\nmacro derived_dimension(name, dims, autodocs=false)\n    uname = Symbol(name,\"Units\")\n    funame = Symbol(name,\"FreeUnits\")\n    name_links = __module__ == Unitful ? \"[`Unitful.Quantity`](@ref), [`Unitful.Level`](@ref)\" : \"`Unitful.Quantity`, `Unitful.Level`\"\n    unit_links = __module__ == Unitful ? \"[`Unitful.Units`](@ref)\" : \"`Unitful.Units`\"\n    funit_links = __module__ == Unitful ? \"[`Unitful.FreeUnits`](@ref)\" : \"`Unitful.FreeUnits`\"\n    name_doc =  \"\"\"\n                    $__module__.$name{T, U}\n\n                A supertype for quantities and levels of dimension `$dims` with a value of type `T` and\n                units `U`.\n\n                See also: $name_links.\n                \"\"\"\n    unit_doc =  \"\"\"\n                    $__module__.$uname{U}\n\n                A supertype for units of dimension `$dims`. Equivalent to `Unitful.Units{U, $dims}`.\n\n                See also: $unit_links.\n                \"\"\"\n    funit_doc = \"\"\"\n                    $__module__.$funame{U}\n\n                A supertype for $funit_links of dimension `$dims`. Equivalent to\n                `Unitful.FreeUnits{U, $dims}`.\n                \"\"\"\n    esc(quote\n        const global ($name){T,U} = Union{\n            $Quantity{T,$dims,U},\n            $Level{L,S,$Quantity{T,$dims,U}} where {L,S}}\n        const global ($uname){U} = $Units{U,$dims}\n        const global ($funame){U} = $FreeUnits{U,$dims}\n        if $autodocs\n            @doc $name_doc $name\n            @doc $unit_doc $uname\n            @doc $funit_doc $funame\n        end\n        nothing\n    end)\nend\n\n\n\"\"\"\n    @refunit(symb, abbr, name, dimension, tf, autodocs=false)\nDefine a reference unit, typically SI. Rather than define\nconversion factors between each and every unit of a given dimension, conversion\nfactors are given between each unit and a reference unit, defined by this macro.\n\nThis macro extends [`Unitful.abbr`](@ref) so that the reference unit can be\ndisplayed in an abbreviated format. If `tf == true`, this macro generates symbols\nfor every power of ten of the unit, using the standard SI prefixes. A `dimension`\nmust be given ([`Unitful.Dimensions`](@ref) object) that specifies the dimension\nof the reference unit. If `autodocs == true`, autogenerated docstrings for\nSI-prefixed units will be added. This option has no effect when `tf == false`.\n\n!!! compat \"Unitful 1.10\"\n    Documenting the resulting unit by adding a docstring before the `@refunit` call requires\n    Unitful 1.10 or later. The `autodocs` argument also requires Unitful 1.10 or later.\n\nIn principle, users can use this macro, but it probably does not make much sense\nto do so. If you define a new (probably unphysical) dimension using\n[`@dimension`](@ref), then this macro will be necessary. With existing dimensions,\nyou will almost certainly cause confusion if you use this macro. One potential\nuse case would be to define a unit system without reference to SI. However,\nthere's no explicit barrier to prevent attempting conversions between SI and this\nhypothetical unit system, which could yield unexpected results.\n\nNote that this macro will also choose the new unit (no power-of-ten prefix) as\nthe default unit for promotion given this dimension.\n\nReturns the [`Unitful.FreeUnits`](@ref) object to which `symb` is bound.\n\nUsage example: `@refunit m \"m\" Meter 𝐋 true`\n\nThis example, found in `src/pkgdefaults.jl`, generates `km`, `m`, `cm`, ...\n\"\"\"\nmacro refunit(symb, abbr, name, dimension, tf, autodocs=false)\n    expr = Expr(:block)\n    n = Meta.quot(Symbol(name))\n\n    push!(expr.args, quote\n        $Unitful.abbr(::$Unit{$n, $dimension}) = $abbr\n    end)\n\n    if tf\n        push!(expr.args, quote\n            Base.@__doc__ $Unitful.@prefixed_unit_symbols $symb $name $dimension (1.0, 1) $autodocs\n        end)\n    else\n        push!(expr.args, quote\n            Base.@__doc__ $Unitful.@unit_symbols $symb $name $dimension (1.0, 1)\n        end)\n    end\n\n    push!(expr.args, quote\n        $preferunits($symb)\n        $symb\n    end)\n\n    esc(expr)\nend\n\n\"\"\"\n    @unit(symb,abbr,name,equals,tf,autodocs=false)\nDefine a unit. Rather than specifying a dimension like in [`@refunit`](@ref),\n`equals` should be a [`Unitful.Quantity`](@ref) equal to one of the unit being\ndefined. If `tf == true`, symbols will be made for each power-of-ten prefix.\nIf `autodocs == true`, autogenerated docstrings for SI-prefixed units will be added.\nThis option has no effect when `tf == false`.\n\n!!! compat \"Unitful 1.10\"\n    Documenting the resulting unit by adding a docstring before the `@unit` call requires\n    Unitful 1.10 or later. The `autodocs` argument also requires Unitful 1.10 or later.\n\nReturns the [`Unitful.FreeUnits`](@ref) object to which `symb` is bound.\n\nUsage example: `@unit mi \"mi\" Mile (201168//125)*m false`\n\nThis example will *not* generate `kmi` (kilomiles).\n\"\"\"\nmacro unit(symb,abbr,name,equals,tf,autodocs=false)\n    expr = Expr(:block)\n    n = Meta.quot(Symbol(name))\n\n    d = :($dimension($equals))\n    basef = :($basefactor($basefactor($unit($equals))...,\n                                 ($equals)/$unit($equals),\n                                 $tensfactor($unit($equals)), 1))\n    push!(expr.args, quote\n        $Unitful.abbr(::$Unit{$n, $d}) = $abbr\n    end)\n\n    if tf\n        push!(expr.args, quote\n            Base.@__doc__ $Unitful.@prefixed_unit_symbols $symb $name $d $basef $autodocs\n        end)\n    else\n        push!(expr.args, quote\n            Base.@__doc__ $Unitful.@unit_symbols $symb $name $d $basef\n        end)\n    end\n\n    push!(expr.args, quote\n        $symb\n    end)\n\n    esc(expr)\nend\n\n\"\"\"\n    @affineunit(symb, abbr, offset)\nMacro for easily defining affine units. `offset` gives the zero of the relative scale\nin terms of an absolute scale; the scaling is the same as the absolute scale. Example:\n`@affineunit °C \"°C\" (27315//100)K` is used internally to define degrees Celsius.\n\n!!! compat \"Unitful 1.10\"\n    Documenting the resulting unit by adding a docstring before the `@affineunit` call\n    requires Unitful 1.10 or later.\n\"\"\"\nmacro affineunit(symb, abbr, offset)\n    s = Symbol(symb)\n    return esc(quote\n        Base.@__doc__ const global $s = $affineunit($offset)\n        $Base.show(io::$IO, ::$genericunit($s)) = $print(io, $abbr)\n    end)\nend\n\nfunction basefactors_expr(m::Module, n, basefactor)\n    if m === Unitful\n        :($(_basefactors(Unitful))[$n] = $basefactor)\n    else\n        # We add the base factor to dictionaries both in Unitful and the other\n        # module so that the factor is available both interactively and with\n        # precompilation.\n        quote\n            $(_basefactors(m))[$n] = $basefactor\n            $(_basefactors(Unitful))[$n] = $basefactor\n        end\n    end\nend\n\n\"\"\"\n    @prefixed_unit_symbols(symb,name,dimension,basefactor,autodocs=false)\nNot called directly by the user. Given a unit symbol and a unit's name,\nwill define units for each possible SI power-of-ten prefix on that unit. If\n`autodocs == true`, it will automatically generate docstrings for these units.\n\n!!! compat \"Unitful 1.10\"\n    Documenting the resulting unit by adding a docstring before the `@prefixed_unit_symbols`\n    call requires Unitful 1.10 or later. The `autodocs` argument also requires Unitful 1.10\n    or later.\n\nExample: `@prefixed_unit_symbols m Meter 𝐋 (1.0,1) true` results in `nm`, `cm`, `m`, `km`, ...\nall getting defined in the calling namespace, with docstrings automatically defined for SI-prefixed units.\n\"\"\"\nmacro prefixed_unit_symbols(symb,name,user_dimension,basefactor,autodocs=false)\n    expr = Expr(:block)\n    n = Meta.quot(Symbol(name))\n\n    for (k,v) in prefixdict\n        s = Symbol(v,symb)\n        u = :($Unit{$n, $user_dimension}($k,1//1))\n        if k == 0\n            ea = quote\n                $(basefactors_expr(__module__, n, basefactor))\n                Base.@__doc__ const global $s = $FreeUnits{($u,), $dimension($u), $nothing}()\n            end\n        else\n            docstring1 = \"\"\"\n                             $__module__.$s\n\n                         A prefixed unit, equal to 10^$k $symb.\n\n                         Dimension: \"\"\"\n            docstring2 = \"\\n\\nSee also: [`$__module__.$symb`](@ref).\"\n            ea = quote\n                $(basefactors_expr(__module__, n, basefactor))\n                const global $s = $FreeUnits{($u,), $dimension($u), $nothing}()\n                if $autodocs\n                    @doc $docstring1*string($user_dimension)*$docstring2 $s\n                end\n            end\n        end\n        push!(expr.args, ea)\n    end\n\n    esc(expr)\nend\n\n\"\"\"\n    @unit_symbols(symb,name)\nNot called directly by the user. Given a unit symbol and a unit's name,\nwill define units without SI power-of-ten prefixes.\n\n!!! compat \"Unitful 1.10\"\n    Documenting the resulting unit by adding a docstring before the `@unit_symbols` call\n    requires Unitful 1.10 or later.\n\nExample: `@unit_symbols ft Foot 𝐋` results in `ft` getting defined but not `kft`.\n\"\"\"\nmacro unit_symbols(symb,name,user_dimension,basefactor)\n    s = Symbol(symb)\n    n = Meta.quot(Symbol(name))\n    u = :($Unit{$n, $user_dimension}(0,1//1))\n    esc(quote\n        $(basefactors_expr(__module__, n, basefactor))\n        Base.@__doc__ const global $s = $FreeUnits{($u,), $dimension($u), $nothing}()\n    end)\nend\n\n\"\"\"\n    preferunits(u0::Units, u::Units...)\nThis function specifies the default fallback units for promotion.\nUnits provided to this function must have a pure dimension of power 1, like `𝐋` or `𝐓`\nbut not `𝐋/𝐓` or `𝐋^2`. The function will complain if this is not the case. Additionally,\nthe function will complain if you provide two units with the same dimension, as a\ncourtesy to the user. Finally, you cannot use affine units such as `°C` with this function.\n\nOnce [`Unitful.upreferred`](@ref) has been called or quantities have been promoted,\nthis function will appear to have no effect.\n\nUsage example: `preferunits(u\"m,s,A,K,cd,kg,mol\"...)`\n\"\"\"\nfunction preferunits(u0::Units, u::Units...)\n\n    units = (u0, u...)\n    any(x->x isa AffineUnits, units) &&\n        error(\"cannot use `Unitful.preferunits` with affine units; try `Unitful.ContextUnits`.\")\n\n    dims = map(dimension, units)\n    if length(union(dims)) != length(dims)\n        error(\"preferunits received more than one unit of a given \",\n        \"dimension.\")\n    end\n\n    for i in eachindex(units)\n        unit, dim = units[i], dims[i]\n        if length(typeof(dim).parameters[1]) > 1\n            error(\"preferunits can only be used with a unit that has a pure \",\n            \"dimension, like 𝐋 or 𝐓 but not 𝐋/𝐓.\")\n        end\n        if length(typeof(dim).parameters[1]) == 1 &&\n            typeof(dim).parameters[1][1].power != 1\n            error(\"preferunits cannot handle powers of pure dimensions except 1. \",\n            \"For instance, it should not be used with units of dimension 𝐋^2.\")\n        end\n        y = typeof(dim).parameters[1][1]\n        promotion[name(y)] = unit\n    end\n\n    # Let's run a quick check for anything where, for instance, current was defined is C/ms and time\n    # was defined in ns. We'll give a warning if this is the case so the user knows they may get\n    # unexpected (though still correct) results. There may be cases where people would want to do this,\n    # so we won't stop them, just let them know they're doing it.\n    ulist = (typeof(i[2]).parameters[1] for i in promotion)\n    check = Dict{Dimensions, Unit}()\n    for a in ulist\n        ulistA = (i^(1/i.power) for i in a)\n        for i in ulistA\n            k = dimension(i)\n            if haskey(check, k)\n                if i!=check[k]\n                    @warn \"Preferred units contain complex units based on units of the same dimension but different scales: \"*string(i)*\" and \"*string(check[k])*\n                    \"\\nThis may be intentional, but otherwise could lead to redundant units, such as ms/s or kg/g\"\n                end\n            else\n                check[k] = i\n            end\n        end\n    end\n\n    nothing\nend\n\n\"\"\"\n    upreferred(x::Number)\n    upreferred(x::Quantity)\nUnit-convert `x` to units which are preferred for the dimensions of `x`.\nIf you are using the factory defaults, this function will unit-convert to a\nproduct of powers of base SI units. If quantity `x` has\n[`Unitful.ContextUnits`](@ref)`(y,z)`, the resulting quantity will have\nunits `ContextUnits(z,z)`.\n\"\"\"\n@inline upreferred(x::Number) = x\n@inline upreferred(x::AbstractQuantity) = uconvert(upreferred(unit(x)), x)\n@inline upreferred(::Missing) = missing\n\n\"\"\"\n    upreferred(x::Units)\nReturn units which are preferred for the dimensions of `x`, which may or may\nnot be equal to `x`, as specified by the [`preferunits`](@ref) function. If you\nare using the factory defaults, this function will return a product of powers of\nbase SI units.\n\"\"\"\n@inline upreferred(x::FreeUnits) = upreferred(dimension(x))\n@inline upreferred(::ContextUnits{N,D,P}) where {N,D,P} = ContextUnits(P(),P())\n@inline upreferred(x::FixedUnits) = x\n\n\"\"\"\n    @logscale(symb,abbr,name,base,prefactor,irp)\nDefine a logarithmic scale. Unlike with units, there is no special treatment for\npower-of-ten prefixes (decibels and bels are defined separately). However, arbitrary\nbases are possible, and computationally appropriate `log` and `exp` functions are used\nin calculations when available (e.g. `log2`, `log10` for base 2 and base 10, respectively).\n\nThis macro defines a `MixedUnits` object identified by symbol `symb`. This can be used\nto construct `Gain` types, e.g. `3*dB`. Additionally, two other `MixedUnits` objects are\ndefined, with symbols `Symbol(symb,\"_rp\")` and `Symbol(symb,\"_p\")`, e.g. `dB_rp` and `dB_p`,\nrespectively. These objects serve nearly the same purpose, but have extra information in\ntheir type that indicates whether they should be considered as root-power ratios or power\nratios upon conversion to pure numbers.\n\nThis macro also defines another macro available as `@symb`. For example, `@dB` in the case\nof decibels. This can be used to construct `Level` objects at parse time. Usage is like\n`@dB 3V/1V`.\n\n`prefactor` is the prefactor out in front of the logarithm for this log scale.\nIn all cases it is defined with respect to taking ratios of power quantities. Just divide\nby two if you want to refer to root-power / field quantities instead.\n\n`irp` (short for \"is root power?\") specifies whether the logarithmic scale is defined\nwith respect to ratios of power or root-power quantities. In short: use `false` if your scale\nis decibel-like, or `true` if your scale is neper-like.\n\nExamples:\n```jldoctest\njulia> using Unitful: V, W\n\njulia> @logscale dΠ \"dΠ\" Decipies π 10 false\ndΠ\n\njulia> @dΠ π*V/1V\n20.0 dΠ (1 V)\n\njulia> dΠ(π*V, 1V)\n20.0 dΠ (1 V)\n\njulia> @dΠ π^2*V/1V\n40.0 dΠ (1 V)\n\njulia> @dΠ π*W/1W\n10.0 dΠ (1 W)\n```\n\"\"\"\nmacro logscale(symb,abbr,name,base,prefactor,irp)\n    quote\n        $Unitful.abbr(::LogInfo{$(QuoteNode(name))}) = $abbr\n\n        const global $(esc(name)) = LogInfo{$(QuoteNode(name)), $base, $prefactor}\n        $Unitful.isrootpower(::Type{$(esc(name))}) = $irp\n\n        const global $(esc(symb)) = MixedUnits{Gain{$(esc(name)), :?}}()\n        const global $(esc(Symbol(symb,\"_rp\"))) = MixedUnits{Gain{$(esc(name)), :rp}}()\n        const global $(esc(Symbol(symb,\"_p\"))) = MixedUnits{Gain{$(esc(name)), :p}}()\n\n        macro $(esc(symb))(::Union{Real,Symbol})\n            throw(ArgumentError(join([\"usage: `@\", $(String(symb)), \" (a)/(b)`\"])))\n        end\n\n        macro $(esc(symb))(expr::Expr)\n            expr.args[1] != :/ &&\n                throw(ArgumentError(join([\"usage: `@\", $(String(symb)), \" (a)/(b)`\"])))\n            length(expr.args) != 3 &&\n                throw(ArgumentError(join([\"usage: `@\", $(String(symb)), \" (a)/(b)`\"])))\n            return Expr(:call, $(esc(symb)), expr.args[2], expr.args[3])\n        end\n\n        macro $(esc(symb))(expr::Expr, tf::Bool)\n            expr.args[1] != :/ &&\n                throw(ArgumentError(join([\"usage: `@\", $(String(symb)), \" (a)/(b)`\"])))\n            length(expr.args) != 3 &&\n                throw(ArgumentError(join([\"usage: `@\", $(String(symb)), \" (a)/(b)`\"])))\n            return Expr(:call, $(esc(symb)), expr.args[2], expr.args[3], tf)\n        end\n\n        function (::$(esc(:typeof))($(esc(symb))))(num::Number, den::Number)\n            dimension(num) != dimension(den) && throw(DimensionError(num,den))\n            dimension(num) == NoDims &&\n                throw(ArgumentError(string(\"to use with dimensionless numbers, pass a \",\n                    \"final `Bool` argument: true if the ratio is a root-power ratio, \",\n                    \"false otherwise.\")))\n            return Level{$(esc(name)), den}(num)\n        end\n\n        function (::$(esc(:typeof))($(esc(symb))))(num::Number, den::Number, irp::Bool)\n            dimension(num) != dimension(den) && throw(DimensionError(num,den))\n            dimension(num) != NoDims &&\n                throw(ArgumentError(string(\"when passing a final Bool argument, \",\n                    \"this can only be used with dimensionless numbers.\")))\n            T = ifelse(irp, RootPowerRatio, PowerRatio)\n            return Level{$(esc(name)), T(den)}(num)\n        end\n\n        function (::$(esc(:typeof))($(esc(symb))))(num::Number, den::Units)\n            $(esc(symb))(num, 1*den)\n        end\n\n        function (::$(esc(:typeof))($(esc(symb))))(num::Number, den::Units, irp::Bool)\n            $(esc(symb))(num, 1*den, irp)\n        end\n\n        $(esc(symb))\n    end\nend\n\n\"\"\"\n    @logunit(symb, abbr, logscale, reflevel)\nDefines a logarithmic unit. For examples see `src/pkgdefaults.jl`.\n\"\"\"\nmacro logunit(symb, abbr, logscale, reflevel)\n    quote\n        $Unitful.abbr(::Level{$(esc(logscale)), $(esc(reflevel))}) = $abbr\n        const global $(esc(symb)) =\n            MixedUnits{Level{$(esc(logscale)), $(esc(reflevel))}}()\n    end\nend\n\n\"\"\"\n    affineunit(x::Quantity)\nReturns a [`Unitful.Units`](@ref) object that can be used to construct affine quantities.\nPrimarily, this is for relative temperatures (as opposed to absolute temperatures,\nwhich transform as usual under unit conversion). To use this function, pass the scale offset,\ne.g. `affineunit(273.15K)` yields a Celsius unit.\n\"\"\"\naffineunit(x::Quantity{T,D,FreeUnits{N,D,nothing}}) where {N,D,T} =\n    FreeUnits{N,D,Affine{-ustrip(x)}}()\n\n\"\"\"\n    @u_str(unit)\nString macro to easily recall units, dimensions, or quantities defined in\nunit modules that have been registered with [`Unitful.register`](@ref).\n\nIf the same symbol is used for a [`Unitful.Units`](@ref) object defined in\ndifferent modules, then the symbol found in the most recently registered module\nwill be used.\n\nNote that what goes inside must be parsable as a valid Julia expression.\nIn other words, `u\"N m\"` will fail if you intended to write `u\"N*m\"`.\n\nExamples:\n\n```jldoctest\njulia> 1.0u\"m/s\"\n1.0 m s^-1\n\njulia> 1.0u\"N*m\"\n1.0 m N\n\njulia> u\"m,kg,s\"\n(m, kg, s)\n\njulia> typeof(1.0u\"m/s\")\nQuantity{Float64, 𝐋 𝐓^-1, Unitful.FreeUnits{(m, s^-1), 𝐋 𝐓^-1, nothing}}\n\njulia> u\"ħ\"\n1.0545718176461565e-34 J s\n```\n\"\"\"\nmacro u_str(unit)\n    ex = Meta.parse(unit)\n    unitmods = [Unitful]\n    for m in Unitful.unitmodules\n        # Find registered unit extension modules which are also loaded by\n        # __module__ (required so that precompilation will work).\n        if isdefined(__module__, nameof(m)) && getfield(__module__, nameof(m)) === m\n            push!(unitmods, m)\n        end\n    end\n    esc(lookup_units(unitmods, ex))\nend\n\n\"\"\"\n    uparse(string [; unit_context=ctx])\n\nParse a string as a unit or quantity. The format for `string` must be a valid\nJulia expression, and any identifiers will be looked up in the context `ctx`,\nwhich may be a `Module` or a vector of `Module`s. By default\n`unit_context=Unitful`.\n\nExamples:\n\n```jldoctest\njulia> uparse(\"m/s\")\nm s^-1\n\njulia> uparse(\"1.0*dB\")\n1.0 dB\n```\n\"\"\"\nfunction uparse(str; unit_context=Unitful)\n    ex = Meta.parse(str)\n    eval(lookup_units(unit_context, ex))\nend\n\nconst allowed_funcs = [:*, :/, :^, :sqrt, :√, :+, :-, ://]\nfunction lookup_units(unitmods, ex::Expr)\n    if ex.head == :call\n        ex.args[1] in allowed_funcs ||\n            throw(ArgumentError(\n                  \"\"\"$(ex.args[1]) is not a valid function call when parsing a unit.\n                   Only the following functions are allowed: $allowed_funcs\"\"\"))\n        for i=2:length(ex.args)\n            if typeof(ex.args[i])==Symbol || typeof(ex.args[i])==Expr\n                ex.args[i]=lookup_units(unitmods, ex.args[i])\n            end\n        end\n        return ex\n    elseif ex.head == :tuple\n        for i=1:length(ex.args)\n            if typeof(ex.args[i])==Symbol\n                ex.args[i]=lookup_units(unitmods, ex.args[i])\n            else\n                throw(ArgumentError(\"Only use symbols inside the tuple.\"))\n            end\n        end\n        return ex\n    else\n        throw(ArgumentError(\"Expr head $(ex.head) must equal :call or :tuple\"))\n    end\nend\n\nfunction lookup_units(unitmods, sym::Symbol)\n    has_unit = m->(isdefined(m,sym) && ustrcheck_bool(getfield(m, sym)))\n    inds = findall(has_unit, unitmods)\n    if isempty(inds)\n        # Check whether unit exists in the global list to give an improved\n        # error message.\n        hintidx = findfirst(has_unit, unitmodules)\n        if hintidx !== nothing\n            hintmod = unitmodules[hintidx]\n            throw(ArgumentError(\n                \"\"\"Symbol `$sym` was found in the globally registered unit module $hintmod\n                   but was not in the provided list of unit modules $(join(unitmods, \", \")).\n\n                   (Consider `using $hintmod` in your module if you are using `@u_str`?)\"\"\"))\n        else\n            throw(ArgumentError(\"Symbol $sym could not be found in unit modules $unitmods\"))\n        end\n    end\n\n    m = unitmods[inds[end]]\n    u = getfield(m, sym)\n\n    any(u != u1 for u1 in getfield.(unitmods[inds[1:(end-1)]], sym)) &&\n        @warn \"\"\"Symbol $sym was found in multiple registered unit modules.\n                 We will use the one from $m.\"\"\"\n    return u\nend\nlookup_units(unitmod::Module, ex::Symbol) = lookup_units([unitmod], ex)\n\nlookup_units(unitmods, literal::Number) = literal\n\nustrcheck_bool(::Number) = true\nustrcheck_bool(::MixedUnits) = true\nustrcheck_bool(::Units) = true\nustrcheck_bool(::Dimensions) = true\nustrcheck_bool(::Quantity) = true\nustrcheck_bool(::Any) = false\n"
  },
  {
    "path": "src/utils.jl",
    "content": "@inline isunitless(::Units) = false\n@inline isunitless(::Units{()}) = true\n\n@inline numtype(::AbstractQuantity{T}) where {T} = T\n@inline numtype(::Type{Q}) where {T, Q<:AbstractQuantity{T}} = T\n\n@inline dimtype(u::Unit{U,D}) where {U,D} = D\n\n\"\"\"\n    ustrip(u::Units, x::Quantity)\n    ustrip(T::Type, u::Units, x::Quantity)\n\nConvert `x` to units `u` using [`uconvert`](@ref) and return the number out the\nfront of the resulting quantity. If `T` is supplied, also `convert` the\nresulting number into type `T`.\n\nThis function is mainly intended for compatibility with packages that don't know\nhow to handle quantities.\n\n```jldoctest\njulia> ustrip(u\"m\", 1u\"mm\") == 1//1000\ntrue\n\njulia> ustrip(Float64, u\"m\", 2u\"mm\") == 0.002\ntrue\n```\n\n`ustrip` supports `InverseFunctions.inverse`:\n\n```jldoctest\njulia> using InverseFunctions: inverse\n\njulia> inverse(Base.Fix1(ustrip, u\"m\"))(5)\n5 m\n```\n\"\"\"\n@inline ustrip(u::Units, x) = ustrip(uconvert(u, x))\n@inline ustrip(T::Type, u::Units, x) = convert(T, ustrip(u, x))\n\n\"\"\"\n    ustrip(x::Number)\n    ustrip(x::Quantity)\n\nReturns the number out in front of any units. The value of `x` may differ from the number\nout front of the units in the case of dimensionless quantities, e.g. `1m/mm != 1`. See\n[`uconvert`](@ref) and the example below. Because the units are removed, information may be\nlost and this should be used with some care — see `ustrip(u,x)` for a safer alternative.\n\n```jldoctest\njulia> ustrip(2u\"μm/m\") == 2\ntrue\n\njulia> uconvert(NoUnits, 2u\"μm/m\") == 2//1000000\ntrue\n```\n\"\"\"\n@inline ustrip(x::Number) = x / unit(x)\n@inline ustrip(x::Quantity) = ustrip(x.val)\n@inline ustrip(x::Missing) = missing\n\n\"\"\"\n    ustrip(x::Array{Q}) where {Q <: Quantity}\nStrip units from an `Array` by reinterpreting to type `T`. The resulting\n`Array` is a not a copy, but rather a unit-stripped view into array `x`. Because the units\nare removed, information may be lost and this should be used with some care.\n\nThis function is provided primarily for compatibility purposes; you could pass\nthe result to PyPlot, for example.\n\n```jldoctest\njulia> a = [1u\"m\", 2u\"m\"]\n2-element Vector{Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}:\n 1 m\n 2 m\n\njulia> b = ustrip(a)\n2-element reinterpret(Int64, ::Vector{Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}):\n 1\n 2\n\njulia> a[1] = 3u\"m\"; b\n2-element reinterpret(Int64, ::Vector{Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}):\n 3\n 2\n```\n\"\"\"\n@inline ustrip(A::Array{Q}) where {Q <: Quantity} = reinterpret(numtype(Q), A)\n\n@deprecate(ustrip(A::AbstractArray{T}) where {T<:Number}, ustrip.(A))\n\n\"\"\"\n    ustrip(A::Diagonal)\n    ustrip(A::Bidiagonal)\n    ustrip(A::Tridiagonal)\n    ustrip(A::SymTridiagonal)\nStrip units from various kinds of matrices by calling `ustrip` on the underlying vectors.\n\"\"\"\nustrip(A::Diagonal) = Diagonal(ustrip(A.diag))\nustrip(A::Bidiagonal) = Bidiagonal(ustrip(A.dv), ustrip(A.ev), ifelse(istriu(A), :U, :L))\nustrip(A::Tridiagonal) = Tridiagonal(ustrip(A.dl), ustrip(A.d), ustrip(A.du))\nustrip(A::SymTridiagonal) = SymTridiagonal(ustrip(A.dv), ustrip(A.ev))\n\n\"\"\"\n    unit(x::Quantity{T,D,U}) where {T,D,U}\n    unit(x::Type{Quantity{T,D,U}}) where {T,D,U}\nReturns the units associated with a `Quantity` or `Quantity` type.\n\nExamples:\n\n```jldoctest\njulia> unit(1.0u\"m\") == u\"m\"\ntrue\n\njulia> unit(typeof(1.0u\"m\")) == u\"m\"\ntrue\n```\n\nSee also: [`logunit`](@ref).\n\"\"\"\n@inline unit(x::AbstractQuantity{T,D,U}) where {T,D,U} = U()\n@inline unit(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U} = U()\n\n\n\"\"\"\n    unit(x::Number)\nReturns the [`NoUnits`](@ref) object to indicate that ordinary numbers have no units. The\nunit is displayed as an empty string.\n\nExamples:\n\n```jldoctest\njulia> typeof(unit(1.0))\nUnitful.FreeUnits{(), NoDims, nothing}\n\njulia> typeof(unit(Float64))\nUnitful.FreeUnits{(), NoDims, nothing}\n\njulia> unit(1.0) == NoUnits\ntrue\n```\n\"\"\"\n@inline unit(x::Number) = NoUnits\n@inline unit(x::Type{T}) where {T <: Number} = NoUnits\n@inline unit(x::Type{Union{Missing, T}}) where T = unit(T)\n@inline unit(x::Type{Missing}) = missing\n@inline unit(x::Missing) = missing\n\n# Prevent infinite recursion, in case unit(Any) is called.\n@inline unit(x::Type{Any}) = throw(ArgumentError(\n    \"unit(Any) was called, which has no meaningful result. This may be due to calling unit(eltype(…)), since eltype has a generic fallback method that returns Any.\"\n))\n\n\"\"\"\n    absoluteunit(::Units)\n    absoluteunit(::Quantity)\nGiven a unit or quantity, which may or may not be affine (e.g. `°C`), return the\ncorresponding unit on the absolute temperature scale (e.g. `K`). Passing a\n[`Unitful.ContextUnits`](@ref) object will return another `ContextUnits` object with\nthe same promotion unit, which may be an affine unit, so take care.\n\"\"\"\nfunction absoluteunit end\n\nabsoluteunit(x::AbstractQuantity{T,D,U}) where {T,D,U} = absoluteunit(U())\nabsoluteunit(::FreeUnits{N,D,A}) where {N,D,A} = FreeUnits{N,D}()\nabsoluteunit(::ContextUnits{N,D,P,A}) where {N,D,P,A} = ContextUnits{N,D,P}()\nabsoluteunit(::FixedUnits{N,D,A}) where {N,D,A} = FixedUnits{N,D}()\n\n\"\"\"\n    dimension(x::Number)\n    dimension(x::Type{T}) where {T<:Number}\nReturns a `Unitful.Dimensions{()}` object to indicate that ordinary\nnumbers are dimensionless. This is a singleton, which we export as `NoDims`.\nThe dimension is displayed as an empty string.\n\nExamples:\n\n```jldoctest\njulia> typeof(dimension(1.0))\nUnitful.Dimensions{()}\n\njulia> typeof(dimension(Float64))\nUnitful.Dimensions{()}\n\njulia> dimension(1.0) == NoDims\ntrue\n```\n\"\"\"\n@inline dimension(x::Number) = NoDims\n@inline dimension(x::Type{T}) where {T <: Number} = NoDims\n@inline dimension(x::Missing) = missing\n@inline dimension(x::Type{Missing}) = missing\n@inline dimension(x::IsRootPowerRatio{S,T}) where {S,T} = dimension(T)\n@inline dimension(x::Level) = dimension(reflevel(x))\n@inline dimension(x::Type{T}) where {T<:Level} = dimension(reflevel(T))\n@inline dimension(x::Gain) = NoDims\n@inline dimension(x::Type{<:Gain}) = NoDims\n\ndimension(a::MixedUnits{L}) where {L} = dimension(L) * dimension(a.units)\n\n\"\"\"\n    dimension(u::Units{U,D}) where {U,D}\nReturns a [`Unitful.Dimensions`](@ref) object corresponding to the dimensions\nof the units, `D`. For a dimensionless combination of units, a\n`Unitful.Dimensions{()}` object is returned (`NoDims`).\n\nExamples:\n\n```jldoctest\njulia> dimension(u\"m\")\n𝐋\n\njulia> typeof(dimension(u\"m\"))\nUnitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}\n\njulia> dimension(u\"m/km\")\nNoDims\n```\n\"\"\"\n@inline dimension(u::Units{U,D}) where {U,D} = D\n\n\"\"\"\n    dimension(x::Quantity{T,D}) where {T,D}\n    dimension(::Type{Quantity{T,D,U}}) where {T,D,U}\nReturns a [`Unitful.Dimensions`](@ref) object `D` corresponding to the\ndimensions of quantity `x`. For a dimensionless [`Unitful.Quantity`](@ref), a\n`Unitful.Dimensions{()}` object is returned (`NoDims`).\n\nExamples:\n\n```jldoctest\njulia> dimension(1.0u\"m\")\n𝐋\n\njulia> typeof(dimension(1.0u\"m/μm\"))\nUnitful.Dimensions{()}\n```\n\"\"\"\n@inline dimension(x::AbstractQuantity{T,D}) where {T,D} = D\n@inline dimension(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U} = D\n\n@deprecate(dimension(x::AbstractArray{T}) where {T<:Number}, dimension.(x))\n@deprecate(dimension(x::AbstractArray{T}) where {T<:Units}, dimension.(x))\n\n\"\"\"\n    struct DimensionError <: Exception\nPhysical dimensions are inconsistent for the attempted operation.\n\"\"\"\nstruct DimensionError <: Exception\n    x\n    y\nend\n\nBase.showerror(io::IO, e::DimensionError) =\n    print(io, \"DimensionError: $(e.x) and $(e.y) are not dimensionally compatible.\");\n\n\"\"\"\n    struct AffineError <: Exception\nAn invalid operation was attempted with affine units / quantities.\n\"\"\"\nstruct AffineError <: Exception\n    x\nend\n\nBase.showerror(io::IO, e::AffineError) = print(io, \"AffineError: $(e.x)\")\n\nfp_overflow_underflow(input, result) =\n    isfinite(input) && !isfinite(result) || !iszero(input) && iszero(result)\n"
  },
  {
    "path": "test/dates.jl",
    "content": "@testset \"Dates stdlib\" begin\n    @testset \"> dimension, numtype, unit\" begin\n        for (T,u) = ((Nanosecond, u\"ns\"), (Microsecond, u\"μs\"), (Millisecond, u\"ms\"),\n                     (Second, u\"s\"), (Minute, u\"minute\"), (Hour, u\"hr\"), (Day, u\"d\"),\n                     (Week, u\"wk\"))\n            @test dimension(T) === dimension(T(1)) === 𝐓\n            @test Unitful.numtype(T) === Unitful.numtype(T(1)) === typeof(Dates.value(T(1)))\n            @test unit(T) === unit(T(1)) === u\n        end\n        for T = (Month, Year)\n            @test_throws MethodError dimension(T)\n            @test_throws MethodError dimension(T(1))\n            @test_throws MethodError Unitful.numtype(T)\n            @test_throws MethodError Unitful.numtype(T(1))\n            @test_throws MethodError unit(T)\n            @test_throws MethodError unit(T(1))\n        end\n\n        for p = (CompoundPeriod, CompoundPeriod(), CompoundPeriod(Day(1)), CompoundPeriod(Day(1), Hour(-1)))\n            @test dimension(p) === 𝐓\n            @test_throws MethodError Unitful.numtype(p)\n            @test_throws MethodError unit(p)\n        end\n    end\n\n    @testset \"> Arithmetic\" begin\n        @testset \">> Addition/subtraction\" begin\n            @test Second(3) + 5u\"ms\" === Int64(3)u\"s\" + 5u\"ms\"\n            @test Second(3) - 5u\"ms\" === Int64(3)u\"s\" - 5u\"ms\"\n            @test 1.0u\"wk\" + Day(3) === 1.0u\"wk\" + Int64(3)u\"d\"\n            @test 1.0u\"wk\" - Day(3) === 1.0u\"wk\" - Int64(3)u\"d\"\n            @test_throws DimensionError 1u\"m\" + Second(1)\n            @test_throws DimensionError 1u\"m\" - Second(1)\n\n            @test Dates.Date(2000, 2, 3) + 24.0u\"hr\" == Dates.Date(2000, 2, 4)\n            @test Dates.Date(2000, 2, 3) + 48.0u\"hr\" == Dates.Date(2000, 2, 5)\n            @test_throws Exception Dates.Date(2000, 2, 3) + 1.0u\"hr\"\n\n            @test Dates.DateTime(2000, 2, 3, 4, 5) + 1.0u\"ns\" == Dates.DateTime(2000, 2, 3, 4, 5)\n            @test Dates.DateTime(2000, 2, 3, 4, 5) + 23.0u\"hr\" == Dates.DateTime(2000, 2, 4, 3, 5)\n            @test Dates.DateTime(2000, 2, 3, 4, 5) + 100.0u\"hr\" == Dates.DateTime(2000, 2, 7, 8, 5)\n            @test Dates.Time(4, 5) + 1.0u\"ps\" == Dates.Time(4, 5)\n            @test Dates.Time(4, 5) + 1.0u\"ms\" == Dates.Time(4, 5, 0, 1)\n            @test Dates.Time(4, 5) + 1.5u\"hr\" == Dates.Time(5, 35)\n            @test Dates.Date(2000, 2, 5) - 48.0u\"hr\" == Dates.Date(2000, 2, 3)\n            @test 24.0u\"hr\" + Dates.Date(2000, 2, 5) == Dates.Date(2000, 2, 6)\n        end\n\n        @testset \">> Multiplication\" begin\n            # Multiplication with quantity\n            @test Int64(3)u\"m\" * Day(1) === Int64(3)u\"m*d\"\n            @test 1.0f0u\"m\" * Microsecond(-2) === -2.0f0u\"m*μs\"\n            @test Hour(4) * Int32(2)u\"m\" === Int64(8)u\"hr*m\"\n            @test Second(5) * (3//2)u\"Hz\" === Rational{Int64}(15,2)u\"s*Hz\"\n            @test Second(5) * 2u\"1/s\" === Int64(10)\n            @test 2.5u\"1/s^2\" * Second(2) === 5.0u\"1/s\"\n            @test_throws AffineError Second(1) * 1u\"°C\"\n            @test_throws AffineError 1u\"°C\" * Second(1)\n            # Multiplication with unit\n            @test Week(5) * u\"Hz\" === Int64(5)u\"wk*Hz\"\n            @test u\"mm\" * Millisecond(20) === Int64(20)u\"mm*ms\"\n            @test u\"ms^-1\" * Millisecond(20) === Int64(20)\n            @test_throws AffineError Second(1) * u\"°C\"\n            @test_throws AffineError u\"°C\" * Second(1)\n            # Multiple factors\n            @test 3.0u\"s\" * Second(3) * (3//1)u\"s\" === 27.0u\"s^3\"\n            @test 3.0u\"s\" * Second(3) * Minute(3) === 27.0u\"s^2*minute\"\n            @test u\"s\" * Second(3) * u\"minute\" === Int64(3)u\"s^2*minute\"\n            @test Second(3) * u\"m\" * u\"m\" === Int64(3)u\"s*m^2\"\n        end\n\n        @testset \">> Division\" begin\n            @testset \">>> /, //\" begin\n                @test Nanosecond(10) / 2u\"m\" === 5.0u\"ns/m\"\n                @test Nanosecond(10) / 2.0f0u\"m\" === 5.0f0u\"ns/m\"\n                @test 5u\"m\" / Hour(2) === 2.5u\"m/hr\"\n                @test 5.0f0u\"m\" / Hour(2) === 2.5f0u\"m/hr\"\n\n                @test Nanosecond(10) // 2u\"m\" === Rational{Int64}(5,1)u\"ns/m\"\n                @test 5u\"m\" // Hour(2) === Rational{Int64}(5,2)u\"m/hr\"\n            end\n\n            @testset \">>> div, fld, cld\" begin\n                @test div(Second(1), 2u\"ms\") == div(1u\"s\", Millisecond(2)) == div(1000, 2)\n                @test div(Second(11), 2u\"s\") == div(11u\"s\", Second(2)) == div(11, 2)\n                @test div(Second(-5), 2u\"s\") == div(-5u\"s\", Second(2)) == div(-5, 2)\n                @test_throws DimensionError div(Second(1), 1u\"m\")\n                @test_throws DimensionError div(1u\"m\", Second(1))\n\n                @test div(4u\"minute\", CompoundPeriod(Minute(1), Second(30))) == div(8, 3)\n                @test div(CompoundPeriod(Minute(4)), 90u\"s\") == div(8, 3)\n                @test_throws DimensionError div(4u\"m\", CompoundPeriod(Minute(1), Second(30)))\n                @test_throws DimensionError div(CompoundPeriod(Minute(4)), 90u\"m\")\n\n                for r = (RoundNearest, RoundNearestTiesAway, RoundNearestTiesUp, RoundToZero, RoundUp, RoundDown)\n                    @test div(Second(11), 2u\"s\", r) == div(11u\"s\", Second(2), r) == div(11, 2, r)\n                    @test div(Second(-5), 2u\"s\", r) == div(-5u\"s\", Second(2), r) == div(-5, 2, r)\n                    @test_throws DimensionError div(Second(1), 1u\"m\", r)\n                    @test_throws DimensionError div(1u\"m\", Second(1), r)\n\n                    if Sys.WORD_SIZE == 32 && r in (RoundNearestTiesAway, RoundNearestTiesUp)\n                        @test_broken div(4u\"minute\", CompoundPeriod(Minute(1), Second(30)), r) == div(8, 3, r)\n                    else\n                        @test div(4u\"minute\", CompoundPeriod(Minute(1), Second(30)), r) == div(8, 3, r)\n                    end\n                    @test div(CompoundPeriod(Minute(4)), 90u\"s\", r) == div(8, 3, r)\n                    @test_throws DimensionError div(4u\"m\", CompoundPeriod(Minute(1), Second(30)), r)\n                    @test_throws DimensionError div(CompoundPeriod(Minute(4)), 90u\"m\", r)\n                end\n\n                @test fld(Second(1), 2u\"ms\") == fld(1u\"s\", Millisecond(2)) == fld(1000, 2)\n                @test fld(Second(11), 2u\"s\") == fld(11u\"s\", Second(2)) == fld(11, 2)\n                @test fld(Second(-5), 2u\"s\") == fld(-5u\"s\", Second(2)) == fld(-5, 2)\n                @test_throws DimensionError fld(Second(1), 1u\"m\")\n                @test_throws DimensionError fld(1u\"m\", Second(1))\n\n                @test fld(4u\"minute\", CompoundPeriod(Minute(1), Second(30))) == fld(8, 3)\n                @test fld(CompoundPeriod(Minute(4)), 90u\"s\") == fld(8, 3)\n                @test_throws DimensionError fld(4u\"m\", CompoundPeriod(Minute(1), Second(30)))\n                @test_throws DimensionError fld(CompoundPeriod(Minute(4)), 90u\"m\")\n\n                @test cld(Second(1), 2u\"ms\") == cld(1u\"s\", Millisecond(2)) == cld(1000, 2)\n                @test cld(Second(11), 2u\"s\") == cld(11u\"s\", Second(2)) == cld(11, 2)\n                @test cld(Second(-5), 2u\"s\") == cld(-5u\"s\", Second(2)) == cld(-5, 2)\n                @test_throws DimensionError cld(Second(1), 1u\"m\")\n                @test_throws DimensionError cld(1u\"m\", Second(1))\n\n                @test cld(4u\"minute\", CompoundPeriod(Minute(1), Second(30))) == cld(8, 3)\n                @test cld(CompoundPeriod(Minute(4)), 90u\"s\") == cld(8, 3)\n                @test_throws DimensionError cld(4u\"m\", CompoundPeriod(Minute(1), Second(30)))\n                @test_throws DimensionError cld(CompoundPeriod(Minute(4)), 90u\"m\")\n            end\n\n            @testset \">>> mod, rem\" begin\n                @test mod(Second(11), 3_000u\"ms\") == mod(11u\"s\", Millisecond(3_000)) == mod(11, 3)u\"s\"\n                @test mod(Second(11), -3u\"s\") == mod(11u\"s\", Second(-3)) == mod(11, -3)u\"s\"\n                @test_throws DimensionError mod(Second(1), 1u\"m\")\n                @test_throws DimensionError mod(1u\"m\", Second(1))\n\n                @test mod(CompoundPeriod(Minute(4)), 90u\"s\") == mod(240, 90)u\"s\"\n                @test_throws MethodError mod(4u\"minute\", CompoundPeriod(Minute(1), Second(30)))\n                @test_throws MethodError mod(4u\"m\", CompoundPeriod(Minute(1), Second(30)))\n                @test_throws DimensionError mod(CompoundPeriod(Minute(4)), 90u\"m\")\n\n                @test rem(Second(11), 3_000u\"ms\") == rem(11u\"s\", Millisecond(3_000)) == rem(11, 3)u\"s\"\n                @test rem(Second(11), -3u\"s\") == rem(11u\"s\", Second(-3)) == rem(11, -3)u\"s\"\n                @test_throws DimensionError rem(Second(1), 1u\"m\")\n                @test_throws DimensionError rem(1u\"m\", Second(1))\n\n                @test rem(CompoundPeriod(Minute(4)), 90u\"s\") == rem(240, 90)u\"s\"\n                @test_throws MethodError rem(4u\"minute\", CompoundPeriod(Minute(1), Second(30)))\n                @test_throws MethodError rem(4u\"m\", CompoundPeriod(Minute(1), Second(30)))\n                @test_throws DimensionError rem(CompoundPeriod(Minute(4)), 90u\"m\")\n\n                for r = (RoundToZero, RoundUp, RoundDown)\n                    @test rem(Second(11), 2u\"s\", r) == rem(11u\"s\", Second(2), r) == rem(11, 2, r)u\"s\"\n                    @test rem(Second(-5), 2u\"s\", r) == rem(-5u\"s\", Second(2), r) == rem(-5, 2, r)u\"s\"\n                    @test_throws DimensionError rem(Second(1), 1u\"m\", r)\n                    @test_throws DimensionError rem(1u\"m\", Second(1), r)\n                end\n            end\n        end\n\n        @testset \">> atan\" begin\n            @test atan(Minute(1), 30u\"s\") == atan(2,1)\n            @test atan(1u\"ms\", Millisecond(5)) == atan(1,5)\n            @test_throws DimensionError atan(Second(1), 1u\"m\")\n            @test_throws DimensionError atan(1u\"m\", Second(1))\n\n            @test atan(CompoundPeriod(Minute(1), Second(30)), 10u\"s\") == atan(9,1)\n            @test atan(1u\"yr\", CompoundPeriod(Day(365), Hour(6))) == atan(1,1)\n            @test_throws DimensionError atan(1u\"m\", CompoundPeriod(Day(365), Hour(6)))\n            @test_throws DimensionError atan(CompoundPeriod(Day(365), Hour(6)), 1u\"m\")\n            @test_throws MethodError atan(1u\"s\", CompoundPeriod(Year(1)))\n            @test_throws MethodError atan(CompoundPeriod(Month(6)), 1u\"s\")\n        end\n    end\n\n    @testset \"> Conversion\" begin\n        @testset \">> uconvert\" begin\n            @test uconvert(u\"s\", Second(3)) === u\"s\"(Second(3)) === Int64(3)u\"s\"\n            @test uconvert(u\"hr\", Minute(90)) === u\"hr\"(Minute(90)) === Rational{Int64}(3,2)u\"hr\"\n            @test uconvert(u\"ns\", Millisecond(-2)) === u\"ns\"(Millisecond(-2)) === Int64(-2_000_000)u\"ns\"\n            @test uconvert(u\"wk\", Hour(1)) === u\"wk\"(Hour(1)) === Rational{Int64}(1,168)u\"wk\"\n            @test_throws DimensionError uconvert(u\"m\", Second(1))\n            @test_throws DimensionError u\"m\"(Second(1))\n\n            @static if Sys.WORD_SIZE == 32\n                @test uconvert(u\"yr\", CompoundPeriod()) === u\"yr\"(CompoundPeriod()) === 0.0u\"yr\"\n            else\n                @test uconvert(u\"yr\", CompoundPeriod()) === u\"yr\"(CompoundPeriod()) === Rational{Int64}(0,1)u\"yr\"\n            end\n            @test uconvert(u\"μs\", CompoundPeriod()) === u\"μs\"(CompoundPeriod()) === Rational{Int64}(0,1)u\"μs\"\n            @test uconvert(u\"ns\", CompoundPeriod()) === u\"ns\"(CompoundPeriod()) === Int64(0)u\"ns\"\n            @test uconvert(u\"ps\", CompoundPeriod()) === u\"ps\"(CompoundPeriod()) === Int64(0)u\"ps\"\n            @static if Sys.WORD_SIZE == 32\n                @test uconvert(u\"yr\", CompoundPeriod(Day(365),Hour(6))) === 1.0u\"yr\"\n                @test u\"yr\"(CompoundPeriod(Day(365),Hour(6))) === 1.0u\"yr\"\n            else\n                @test uconvert(u\"yr\", CompoundPeriod(Day(365),Hour(6))) === Rational{Int64}(1,1)u\"yr\"\n                @test u\"yr\"(CompoundPeriod(Day(365),Hour(6))) === Rational{Int64}(1,1)u\"yr\"\n            end\n            @test uconvert(u\"μs\", CompoundPeriod(Day(365),Hour(6))) === Rational{Int64}(31_557_600_000_000,1)u\"μs\"\n            @test u\"μs\"(CompoundPeriod(Day(365),Hour(6))) === Rational{Int64}(31_557_600_000_000,1)u\"μs\"\n            @test uconvert(u\"ns\", CompoundPeriod(Day(365),Hour(6))) === Int64(31_557_600_000_000_000)u\"ns\"\n            @test u\"ns\"(CompoundPeriod(Day(365),Hour(6))) === Int64(31_557_600_000_000_000)u\"ns\"\n            @test uconvert(u\"ps\", CompoundPeriod(Week(1),Hour(-1))) === Int64(601_200_000_000_000_000)u\"ps\"\n            @test u\"ps\"(CompoundPeriod(Week(1),Hour(-1))) === Int64(601_200_000_000_000_000)u\"ps\"\n            @test_throws DimensionError uconvert(u\"m\", CompoundPeriod(Day(365),Hour(6)))\n            @test_throws DimensionError u\"m\"(CompoundPeriod(Day(365),Hour(6)))\n            @test_throws MethodError uconvert(u\"yr\", CompoundPeriod(Year(1),Day(1)))\n            @test_throws MethodError u\"yr\"(CompoundPeriod(Year(1),Day(1)))\n            @test_throws MethodError uconvert(u\"s\", CompoundPeriod(Month(1),Day(1)))\n            @test_throws MethodError u\"s\"(CompoundPeriod(Month(1),Day(1)))\n        end\n\n        @testset \">> ustrip\" begin\n            for (T,u) = ((Nanosecond, u\"ns\"), (Microsecond, u\"μs\"), (Millisecond, u\"ms\"),\n                         (Second, u\"s\"), (Minute, u\"minute\"), (Hour, u\"hr\"), (Day, u\"d\"),\n                (Week, u\"wk\"))\n                @test ustrip(T(5)) === ustrip(u, T(5)) === Int64(5)\n            end\n            @test ustrip(u\"ms\", Second(1)) === Int64(1000)\n            @test ustrip(u\"wk\", Day(1)) === Rational{Int64}(1,7)\n            @test_throws DimensionError ustrip(u\"m\", Nanosecond(1))\n            @test_throws MethodError ustrip(Month(1))\n            @test_throws MethodError ustrip(Year(1))\n            @test_throws MethodError ustrip(u\"s\", Month(1))\n            @test_throws MethodError ustrip(u\"yr\", Year(1))\n\n            @static if Sys.WORD_SIZE == 32\n                @test ustrip(u\"yr\", CompoundPeriod()) === 0.0\n            else\n                @test ustrip(u\"yr\", CompoundPeriod()) === Rational{Int64}(0,1)\n            end\n            @test ustrip(u\"μs\", CompoundPeriod()) === Rational{Int64}(0,1)\n            @test ustrip(u\"ns\", CompoundPeriod()) === Int64(0)\n            @test ustrip(u\"ps\", CompoundPeriod()) === Int64(0)\n            @static if Sys.WORD_SIZE == 32\n                @test ustrip(u\"yr\", CompoundPeriod(Day(365),Hour(6))) === 1.0\n            else\n                @test ustrip(u\"yr\", CompoundPeriod(Day(365),Hour(6))) === Rational{Int64}(1,1)\n            end\n            @test ustrip(u\"μs\", CompoundPeriod(Day(365),Hour(6))) === Rational{Int64}(31_557_600_000_000,1)\n            @test ustrip(u\"ns\", CompoundPeriod(Day(365),Hour(6))) === Int64(31_557_600_000_000_000)\n            @test ustrip(u\"ps\", CompoundPeriod(Week(1),Hour(-1))) === Int64(601_200_000_000_000_000)\n            @test_throws DimensionError ustrip(u\"m\", CompoundPeriod(Day(365),Hour(6)))\n            @test_throws MethodError ustrip(CompoundPeriod())\n            @test_throws MethodError ustrip(CompoundPeriod(Second(1)))\n            @test_throws MethodError ustrip(CompoundPeriod(Week(1), Hour(-1)))\n            @test_throws MethodError ustrip(u\"yr\", CompoundPeriod(Year(1)))\n            @test_throws MethodError ustrip(u\"yr\", CompoundPeriod(Month(1)))\n        end\n\n        @testset \">> Constructors/convert\" begin\n            for (T,u) = ((Nanosecond, u\"ns\"), (Microsecond, u\"μs\"), (Millisecond, u\"ms\"),\n                         (Second, u\"s\"), (Minute, u\"minute\"), (Hour, u\"hr\"), (Day, u\"d\"),\n                (Week, u\"wk\"))\n                @test Quantity(T(1)) === convert(Quantity, T(1)) === Int64(1)*u\n                @test Quantity{Float64,𝐓,typeof(u)}(T(2)) === convert(Quantity{Float64,𝐓,typeof(u)}, T(2)) === 2.0u\n                @test Quantity{Rational{Int64},𝐓,typeof(u)}(T(3)) === convert(Quantity{Rational{Int64},𝐓,typeof(u)}, T(3)) === Rational{Int64}(3,1)u\n            end\n            @test Quantity{Float64,𝐓,typeof(u\"d\")}(Hour(6)) === convert(typeof(1.0u\"d\"), Hour(6)) === 0.25u\"d\"\n            @test_throws InexactError Quantity{Int64,𝐓,typeof(u\"d\")}(Hour(6))\n            @test_throws InexactError convert(typeof(1u\"d\"), Hour(6))\n            @test_throws DimensionError Quantity{Float64,𝐋,typeof(u\"m\")}(Hour(6))\n            @test_throws DimensionError convert(typeof(1.0u\"m\"), Week(1))\n            @test_throws MethodError Quantity{Float64,𝐓,typeof(u\"d\")}(Month(1))\n            @test_throws MethodError Quantity{Float64,𝐓,typeof(u\"d\")}(Year(1))\n            @test_throws MethodError convert(typeof(1u\"d\"), Month(1))\n            @test_throws MethodError convert(typeof(1u\"d\"), Year(1))\n\n            @test Week(4u\"wk\") === convert(Week, 4u\"wk\") === Week(4)\n            @test Microsecond((3//2)u\"ms\") === convert(Microsecond, (3//2)u\"ms\") === Microsecond(1500)\n            @test Millisecond(1.0u\"s\") === convert(Millisecond, 1.0u\"s\") === Millisecond(1000)\n            @test Second(1.0u\"s\") === convert(Second, 1.0u\"s\") === Second(1)\n            @test Day(3u\"wk\") === convert(Day, 3u\"wk\") === Day(21)\n            @test_throws InexactError Second(1.5u\"s\")\n            @test_throws InexactError convert(Second, 1.5u\"s\")\n            @test_throws InexactError Second(1u\"ms\")\n            @test_throws InexactError convert(Second, 1u\"ms\")\n            @test_throws DimensionError Second(1u\"m\")\n            @test_throws DimensionError convert(Second, 1u\"m\")\n            @test_throws DimensionError Month(1u\"s\") # Doesn't throw MethodError because Month(::Number) exists\n            @test_throws DimensionError Year(1u\"s\") # Doesn't throw MethodError because Year(::Number) exists\n            @test_throws MethodError convert(Month, 1u\"s\")\n            @test_throws MethodError convert(Year, 1u\"s\")\n\n            for T = (Quantity{Rational{Int64},𝐓,typeof(u\"yr\")},\n                     Quantity{Float64,𝐓,typeof(u\"s\")},\n                     Quantity{Int64,𝐓,typeof(u\"ns\")})\n                @test T(CompoundPeriod()) === convert(T, CompoundPeriod()) === T(0u\"s\")\n                @test T(CompoundPeriod(Day(365), Hour(6))) === convert(T, CompoundPeriod(Day(365), Hour(6))) === T(1u\"yr\")\n                @test T(CompoundPeriod(Week(1), Hour(-1))) === convert(T, CompoundPeriod(Week(1), Hour(-1))) === T(167u\"hr\")\n                @test_throws MethodError T(CompoundPeriod(Month(1)))\n                @test_throws MethodError T(CompoundPeriod(Year(1)))\n                @test_throws MethodError convert(T, CompoundPeriod(Month(1)))\n                @test_throws MethodError convert(T, CompoundPeriod(Year(1)))\n            end\n            @test_throws InexactError Quantity{Int64,𝐓,typeof(u\"d\")}(CompoundPeriod(Day(1),Hour(6)))\n            @test_throws InexactError convert(typeof(1u\"d\"), CompoundPeriod(Day(1),Hour(1)))\n            @test_throws DimensionError Quantity{Float64,𝐋,typeof(u\"m\")}(CompoundPeriod(Day(365), Hour(6)))\n            @test_throws DimensionError convert(typeof(1.0u\"m\"), CompoundPeriod(Day(365), Hour(6)))\n        end\n    end\n\n    @testset \"> Rounding\" begin\n        @test round(Second, -1.2u\"s\") === round(Second, -1.2u\"s\", RoundNearest) === Second(-1)\n        @test round(Second, -1.5u\"s\") === round(Second, -1.5u\"s\", RoundNearest) === Second(-2)\n        @test round(Second, -0.5u\"s\") === round(Second, -0.5u\"s\", RoundNearest) === Second(0)\n        @test round(Minute,   45u\"s\") === round(Minute,   45u\"s\", RoundNearest) === Minute(1)\n        @test round(Minute,   90u\"s\") === round(Minute,   90u\"s\", RoundNearest) === Minute(2)\n        @test round(Minute,  150u\"s\") === round(Minute,  150u\"s\", RoundNearest) === Minute(2)\n        @test round(Second, -1.2u\"s\", RoundNearestTiesAway) === Second(-1)\n        @test round(Second, -1.5u\"s\", RoundNearestTiesAway) === Second(-2)\n        @test round(Second, -0.5u\"s\", RoundNearestTiesAway) === Second(-1)\n        @test round(Minute,   45u\"s\", RoundNearestTiesAway) === Minute(1)\n        @test round(Minute,   90u\"s\", RoundNearestTiesAway) === Minute(2)\n        @test round(Minute,  150u\"s\", RoundNearestTiesAway) === Minute(3)\n        @test round(Second, -1.2u\"s\", RoundNearestTiesUp) === Second(-1)\n        @test round(Second, -1.5u\"s\", RoundNearestTiesUp) === Second(-1)\n        @test round(Second, -0.5u\"s\", RoundNearestTiesUp) === Second(0)\n        @test round(Minute,   45u\"s\", RoundNearestTiesUp) === Minute(1)\n        @test round(Minute,   90u\"s\", RoundNearestTiesUp) === Minute(2)\n        @test round(Minute,  150u\"s\", RoundNearestTiesUp) === Minute(3)\n        @test trunc(Second, -1.2u\"s\") === round(Second, -1.2u\"s\", RoundToZero) === Second(-1)\n        @test trunc(Second, -1.5u\"s\") === round(Second, -1.5u\"s\", RoundToZero) === Second(-1)\n        @test trunc(Second, -0.5u\"s\") === round(Second, -0.5u\"s\", RoundToZero) === Second(0)\n        @test ceil(Second, -1.2u\"s\")  === round(Second, -1.2u\"s\", RoundUp) === Second(-1)\n        @test ceil(Second, -1.5u\"s\")  === round(Second, -1.5u\"s\", RoundUp) === Second(-1)\n        @test ceil(Second, -0.5u\"s\")  === round(Second, -0.5u\"s\", RoundUp) === Second(0)\n        @test floor(Second, -1.2u\"s\") === round(Second, -1.2u\"s\", RoundDown) === Second(-2)\n        @test floor(Second, -1.5u\"s\") === round(Second, -1.5u\"s\", RoundDown) === Second(-2)\n        @test floor(Second, -0.5u\"s\") === round(Second, -0.5u\"s\", RoundDown) === Second(-1)\n        @test trunc(Minute,  45u\"s\") === round(Minute,   45u\"s\", RoundToZero) === Minute(0)\n        @test trunc(Minute,  90u\"s\") === round(Minute,   90u\"s\", RoundToZero) === Minute(1)\n        @test trunc(Minute, 150u\"s\") === round(Minute,  150u\"s\", RoundToZero) === Minute(2)\n        @test ceil(Minute,  45u\"s\")  === round(Minute,   45u\"s\", RoundUp) === Minute(1)\n        @test ceil(Minute,  90u\"s\")  === round(Minute,   90u\"s\", RoundUp) === Minute(2)\n        @test ceil(Minute, 150u\"s\")  === round(Minute,  150u\"s\", RoundUp) === Minute(3)\n        @test floor(Minute,  45u\"s\") === round(Minute,   45u\"s\", RoundDown) === Minute(0)\n        @test floor(Minute,  90u\"s\") === round(Minute,   90u\"s\", RoundDown) === Minute(1)\n        @test floor(Minute, 150u\"s\") === round(Minute,  150u\"s\", RoundDown) === Minute(2)\n        @test_throws DimensionError round(Second, 1u\"m\")\n        @test_throws DimensionError round(Second, 1u\"m\", RoundNearestTiesUp)\n        @test_throws DimensionError trunc(Second, 1u\"m\")\n        @test_throws DimensionError ceil(Second, 1u\"m\")\n        @test_throws DimensionError floor(Second, 1u\"m\")\n\n        @test round(u\"minute\", Second(-50)) === Rational{Int64}(-1,1)u\"minute\"\n        @test round(u\"minute\", Second(-90)) === Rational{Int64}(-2,1)u\"minute\"\n        @test round(u\"minute\", Second(150)) === Rational{Int64}(2,1)u\"minute\"\n        @test round(u\"minute\", Second(-50), RoundNearest) === Rational{Int64}(-1,1)u\"minute\"\n        @test round(u\"minute\", Second(-90), RoundNearest) === Rational{Int64}(-2,1)u\"minute\"\n        @test round(u\"minute\", Second(150), RoundNearest) === Rational{Int64}(2,1)u\"minute\"\n        @test round(u\"minute\", Second(-50), RoundNearestTiesAway) === Rational{Int64}(-1,1)u\"minute\"\n        @test round(u\"minute\", Second(-90), RoundNearestTiesAway) === Rational{Int64}(-2,1)u\"minute\"\n        @test round(u\"minute\", Second(150), RoundNearestTiesAway) === Rational{Int64}(3,1)u\"minute\"\n        @test round(u\"minute\", Second(-50), RoundNearestTiesUp) === Rational{Int64}(-1,1)u\"minute\"\n        @test round(u\"minute\", Second(-90), RoundNearestTiesUp) === Rational{Int64}(-1,1)u\"minute\"\n        @test round(u\"minute\", Second(150), RoundNearestTiesUp) === Rational{Int64}(3,1)u\"minute\"\n\n        @test trunc(u\"minute\", Second(-50)) === round(u\"minute\", Second(-50), RoundToZero) === Rational{Int64}(0,1)u\"minute\"\n        @test trunc(u\"minute\", Second(-90)) === round(u\"minute\", Second(-90), RoundToZero) === Rational{Int64}(-1,1)u\"minute\"\n        @test trunc(u\"minute\", Second(150)) === round(u\"minute\", Second(150), RoundToZero) === Rational{Int64}(2,1)u\"minute\"\n\n        @test ceil(u\"minute\", Second(-50))  === round(u\"minute\", Second(-50), RoundUp) === Rational{Int64}(0,1)u\"minute\"\n        @test ceil(u\"minute\", Second(-90))  === round(u\"minute\", Second(-90), RoundUp) === Rational{Int64}(-1,1)u\"minute\"\n        @test ceil(u\"minute\", Second(150))  === round(u\"minute\", Second(150), RoundUp) === Rational{Int64}(3,1)u\"minute\"\n\n        @test floor(u\"minute\", Second(-50)) === round(u\"minute\", Second(-50), RoundDown) === Rational{Int64}(-1,1)u\"minute\"\n        @test floor(u\"minute\", Second(-90)) === round(u\"minute\", Second(-90), RoundDown) === Rational{Int64}(-2,1)u\"minute\"\n        @test floor(u\"minute\", Second(150)) === round(u\"minute\", Second(150), RoundDown) === Rational{Int64}(2,1)u\"minute\"\n\n        @test_throws DimensionError round(u\"m\", Second(1))\n        @test_throws DimensionError round(u\"m\", Second(1), RoundNearestTiesAway)\n        @test_throws DimensionError trunc(u\"m\", Second(1))\n        @test_throws DimensionError ceil(u\"m\", Second(1))\n        @test_throws DimensionError floor(u\"m\", Second(1))\n\n        T = @static Sys.WORD_SIZE == 32 ? Float64 : Rational{Int64}\n        @test round(u\"minute\", CompoundPeriod(Minute(-1), Second(10))) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-2), Second(30))) === T(-2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(3), Second(-30))) === T(2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-1), Second(10)), RoundNearest) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-2), Second(30)), RoundNearest) === T(-2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(3), Second(-30)), RoundNearest) === T(2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-1), Second(10)), RoundNearestTiesAway) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-2), Second(30)), RoundNearestTiesAway) === T(-2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(3), Second(-30)), RoundNearestTiesAway) === T(3)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-1), Second(10)), RoundNearestTiesUp) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-2), Second(30)), RoundNearestTiesUp) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(3), Second(-30)), RoundNearestTiesUp) === T(3)u\"minute\"\n        @test trunc(u\"minute\", CompoundPeriod(Minute(-1), Second(10))) === -T(0)u\"minute\"\n        @test trunc(u\"minute\", CompoundPeriod(Minute(-2), Second(30))) === T(-1)u\"minute\"\n        @test trunc(u\"minute\", CompoundPeriod(Minute(3), Second(-30))) === T(2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-1), Second(10)), RoundToZero) === -T(0)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-2), Second(30)), RoundToZero) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(3), Second(-30)), RoundToZero) === T(2)u\"minute\"\n        @test ceil(u\"minute\", CompoundPeriod(Minute(-1), Second(10)))  === -T(0)u\"minute\"\n        @test ceil(u\"minute\", CompoundPeriod(Minute(-2), Second(30)))  === T(-1)u\"minute\"\n        @test ceil(u\"minute\", CompoundPeriod(Minute(3), Second(-30)))  === T(3)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-1), Second(10)), RoundUp) === -T(0)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-2), Second(30)), RoundUp) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(3), Second(-30)), RoundUp) === T(3)u\"minute\"\n        @test floor(u\"minute\", CompoundPeriod(Minute(-1), Second(10))) === T(-1)u\"minute\"\n        @test floor(u\"minute\", CompoundPeriod(Minute(-2), Second(30))) === T(-2)u\"minute\"\n        @test floor(u\"minute\", CompoundPeriod(Minute(3), Second(-30))) === T(2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-1), Second(10)), RoundDown) === T(-1)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(-2), Second(30)), RoundDown) === T(-2)u\"minute\"\n        @test round(u\"minute\", CompoundPeriod(Minute(3), Second(-30)), RoundDown) === T(2)u\"minute\"\n        @test_throws MethodError round(u\"s\", CompoundPeriod(Year(1)))\n        @test_throws MethodError round(u\"s\", CompoundPeriod(Year(1)), RoundNearestTiesAway)\n        @test_throws MethodError trunc(u\"s\", CompoundPeriod(Year(1)))\n        @test_throws MethodError ceil(u\"s\", CompoundPeriod(Year(1)))\n        @test_throws MethodError floor(u\"s\", CompoundPeriod(Year(1)))\n        @test_throws MethodError round(u\"s\", CompoundPeriod(Month(1)))\n        @test_throws MethodError round(u\"s\", CompoundPeriod(Month(1)), RoundNearestTiesAway)\n        @test_throws MethodError trunc(u\"s\", CompoundPeriod(Month(1)))\n        @test_throws MethodError ceil(u\"s\", CompoundPeriod(Month(1)))\n        @test_throws MethodError floor(u\"s\", CompoundPeriod(Month(1)))\n        @test_throws DimensionError round(u\"m\", CompoundPeriod(Second(1)))\n        @test_throws DimensionError round(u\"m\", CompoundPeriod(Second(1)), RoundNearestTiesAway)\n        @test_throws DimensionError trunc(u\"m\", CompoundPeriod(Second(1)))\n        @test_throws DimensionError ceil(u\"m\", CompoundPeriod(Second(1)))\n        @test_throws DimensionError floor(u\"m\", CompoundPeriod(Second(1)))\n\n        @test round(u\"wk\", Day(10), digits=1) === 1.4u\"wk\"\n        @test round(u\"wk\", Day(10), sigdigits=3) === 1.43u\"wk\"\n        @test round(u\"wk\", Day(10), RoundUp, digits=1) === 1.5u\"wk\"\n        @test round(u\"wk\", Day(10), RoundDown, sigdigits=3) === 1.42u\"wk\"\n        @test round(u\"wk\", Day(10), RoundUp, digits=2, base=2) === 1.5u\"wk\"\n        @test round(u\"wk\", Day(10), RoundToZero, digits=2, base=2) === 1.25u\"wk\"\n        @test floor(u\"wk\", Day(10), sigdigits=3) === 1.42u\"wk\"\n        @test ceil(u\"wk\", Day(10), digits=2, base=2) === 1.5u\"wk\"\n        @test trunc(u\"wk\", Day(10), digits=2, base=2) === 1.25u\"wk\"\n        @test_throws DimensionError round(u\"m\", Day(10), digits=1)\n        @test_throws DimensionError round(u\"m\", Day(10), sigdigits=3, base=2)\n        @test_throws DimensionError round(u\"m\", Day(10), RoundUp, digits=1)\n        @test_throws DimensionError trunc(u\"m\", Day(10), digits=1)\n        @test_throws DimensionError ceil(u\"m\", Day(10), sigdigits=3)\n        @test_throws DimensionError floor(u\"m\", Day(10), digits=1, base=2)\n\n        @test round(u\"wk\", CompoundPeriod(Week(1), Day(3)), digits=1) === 1.4u\"wk\"\n        @test round(u\"wk\", CompoundPeriod(Week(1), Day(3)), sigdigits=3) === 1.43u\"wk\"\n        @test round(u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundUp, digits=1) === 1.5u\"wk\"\n        @test round(u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundDown, sigdigits=3) === 1.42u\"wk\"\n        @test round(u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundUp, digits=2, base=2) === 1.5u\"wk\"\n        @test round(u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundToZero, digits=2, base=2) === 1.25u\"wk\"\n        @test floor(u\"wk\", CompoundPeriod(Week(1), Day(3)), sigdigits=3) === 1.42u\"wk\"\n        @test ceil(u\"wk\", CompoundPeriod(Week(1), Day(3)), digits=2, base=2) === 1.5u\"wk\"\n        @test trunc(u\"wk\", CompoundPeriod(Week(1), Day(3)), digits=2, base=2) === 1.25u\"wk\"\n        @test_throws MethodError round(u\"wk\", CompoundPeriod(Year(1)), digits=1)\n        @test_throws MethodError floor(u\"wk\", CompoundPeriod(Year(1)), sigdigits=3)\n        @test_throws MethodError ceil(u\"wk\", CompoundPeriod(Year(1)), digits=2, base=2)\n        @test_throws MethodError trunc(u\"wk\", CompoundPeriod(Year(1)), digits=2, base=2)\n        @test_throws MethodError round(u\"wk\", CompoundPeriod(Month(1)), digits=1)\n        @test_throws MethodError floor(u\"wk\", CompoundPeriod(Month(1)), sigdigits=3)\n        @test_throws MethodError ceil(u\"wk\", CompoundPeriod(Month(1)), digits=2, base=2)\n        @test_throws MethodError trunc(u\"wk\", CompoundPeriod(Month(1)), digits=2, base=2)\n        @test_throws DimensionError round(u\"m\", CompoundPeriod(Week(1), Day(3)), digits=1)\n        @test_throws DimensionError round(u\"m\", CompoundPeriod(Week(1), Day(3)), sigdigits=3, base=2)\n        @test_throws DimensionError round(u\"m\", CompoundPeriod(Week(1), Day(3)), RoundUp, digits=1)\n        @test_throws DimensionError trunc(u\"m\", CompoundPeriod(Week(1), Day(3)), digits=1)\n        @test_throws DimensionError ceil(u\"m\", CompoundPeriod(Week(1), Day(3)), sigdigits=3)\n        @test_throws DimensionError floor(u\"m\", CompoundPeriod(Week(1), Day(3)), digits=1, base=2)\n\n        @test round(Int, u\"minute\", Second(-50)) === -1u\"minute\"\n        @test round(Float32, u\"minute\", Second(-50)) === -1.0f0u\"minute\"\n        @test round(Int, u\"minute\", Second(50), RoundDown) === 0u\"minute\"\n        @test round(Int, u\"minute\", Second(50), RoundUp) === 1u\"minute\"\n        @test round(Int, u\"minute\", Second(50), RoundToZero) === 0u\"minute\"\n        @test floor(Int, u\"minute\", Second(50)) === 0u\"minute\"\n        @test ceil(Int, u\"minute\", Second(50)) === 1u\"minute\"\n        @test trunc(Int, u\"minute\", Second(50)) === 0u\"minute\"\n        @test round(Float32, u\"minute\", Second(50), RoundDown) === 0.0f0u\"minute\"\n        @test round(Float32, u\"minute\", Second(50), RoundUp) === 1.0f0u\"minute\"\n        @test round(Float32, u\"minute\", Second(50), RoundToZero) === 0.0f0u\"minute\"\n        @test floor(Float32, u\"minute\", Second(50)) === 0.0f0u\"minute\"\n        @test ceil(Float32, u\"minute\", Second(50)) === 1.0f0u\"minute\"\n        @test trunc(Float32, u\"minute\", Second(50)) === 0.0f0u\"minute\"\n        @test round(Float32, u\"wk\", Day(10), digits=1) === 1.4f0u\"wk\"\n        @test round(Float32, u\"wk\", Day(10), sigdigits=3) === 1.43f0u\"wk\"\n        @test round(Float32, u\"wk\", Day(10), RoundUp, digits=1) === 1.5f0u\"wk\"\n        @test round(Float32, u\"wk\", Day(10), RoundDown, sigdigits=3) === 1.42f0u\"wk\"\n        @test round(Float32, u\"wk\", Day(10), RoundUp, digits=2, base=2) === 1.5f0u\"wk\"\n        @test round(Float32, u\"wk\", Day(10), RoundToZero, digits=2, base=2) === 1.25f0u\"wk\"\n        @test floor(Float32, u\"wk\", Day(10), sigdigits=3) === 1.42f0u\"wk\"\n        @test ceil(Float32, u\"wk\", Day(10), digits=2, base=2) === 1.5f0u\"wk\"\n        @test trunc(Float32, u\"wk\", Day(10), digits=2, base=2) === 1.25f0u\"wk\"\n        @test_throws DimensionError round(Float32, u\"m\", Second(-50))\n        @test_throws DimensionError round(Float32, u\"m\", Second(-50), RoundDown)\n        @test_throws DimensionError round(Float32, u\"m\", Second(-50), digits=1)\n        @test_throws DimensionError round(Float32, u\"m\", Second(-50), RoundDown, sigdigits=3)\n        @test_throws DimensionError floor(Float32, u\"m\", Second(-50))\n        @test_throws DimensionError ceil(Float32, u\"m\", Second(-50), digits=1)\n        @test_throws DimensionError trunc(Float32, u\"m\", Second(-50), sigdigits=3, base=2)\n\n        @test round(Int, u\"minute\", CompoundPeriod(Minute(-1), Second(10))) === -1u\"minute\"\n        @test round(Float32, u\"minute\", CompoundPeriod(Minute(-1), Second(10))) === -1.0f0u\"minute\"\n        @test round(Int, u\"minute\", CompoundPeriod(Minute(1), Second(-10)), RoundDown) === 0u\"minute\"\n        @test round(Int, u\"minute\", CompoundPeriod(Minute(1), Second(-10)), RoundUp) === 1u\"minute\"\n        @test round(Int, u\"minute\", CompoundPeriod(Minute(1), Second(-10)), RoundToZero) === 0u\"minute\"\n        @test floor(Int, u\"minute\", CompoundPeriod(Minute(1), Second(-10))) === 0u\"minute\"\n        @test ceil(Int, u\"minute\", CompoundPeriod(Minute(1), Second(-10))) === 1u\"minute\"\n        @test trunc(Int, u\"minute\", CompoundPeriod(Minute(1), Second(-10))) === 0u\"minute\"\n        @test round(Float32, u\"minute\", CompoundPeriod(Minute(1), Second(-10)), RoundDown) === 0.0f0u\"minute\"\n        @test round(Float32, u\"minute\", CompoundPeriod(Minute(1), Second(-10)), RoundUp) === 1.0f0u\"minute\"\n        @test round(Float32, u\"minute\", CompoundPeriod(Minute(1), Second(-10)), RoundToZero) === 0.0f0u\"minute\"\n        @test floor(Float32, u\"minute\", CompoundPeriod(Minute(1), Second(-10))) === 0.0f0u\"minute\"\n        @test ceil(Float32, u\"minute\", CompoundPeriod(Minute(1), Second(-10))) === 1.0f0u\"minute\"\n        @test trunc(Float32, u\"minute\", CompoundPeriod(Minute(1), Second(-10))) === 0.0f0u\"minute\"\n        @test round(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), digits=1) === 1.4f0u\"wk\"\n        @test round(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), sigdigits=3) === 1.43f0u\"wk\"\n        @test round(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundUp, digits=1) === 1.5f0u\"wk\"\n        @test round(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundDown, sigdigits=3) === 1.42f0u\"wk\"\n        @test round(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundUp, digits=2, base=2) === 1.5f0u\"wk\"\n        @test round(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), RoundToZero, digits=2, base=2) === 1.25f0u\"wk\"\n        @test floor(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), sigdigits=3) === 1.42f0u\"wk\"\n        @test ceil(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), digits=2, base=2) === 1.5f0u\"wk\"\n        @test trunc(Float32, u\"wk\", CompoundPeriod(Week(1), Day(3)), digits=2, base=2) === 1.25f0u\"wk\"\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Year(1)))\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Year(1)), RoundDown)\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Year(1)), digits=1)\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Year(1)), RoundDown, sigdigits=3)\n        @test_throws MethodError floor(Float32, u\"yr\", CompoundPeriod(Year(1)))\n        @test_throws MethodError  ceil(Float32, u\"yr\", CompoundPeriod(Year(1)), digits=1)\n        @test_throws MethodError trunc(Float32, u\"yr\", CompoundPeriod(Year(1)), sigdigits=3, base=2)\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Month(1)))\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Month(1)), RoundDown)\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Month(1)), digits=1)\n        @test_throws MethodError round(Float32, u\"yr\", CompoundPeriod(Month(1)), RoundDown, sigdigits=3)\n        @test_throws MethodError floor(Float32, u\"yr\", CompoundPeriod(Month(1)))\n        @test_throws MethodError  ceil(Float32, u\"yr\", CompoundPeriod(Month(1)), digits=1)\n        @test_throws MethodError trunc(Float32, u\"yr\", CompoundPeriod(Month(1)), sigdigits=3, base=2)\n        @test_throws DimensionError round(Float32, u\"m\", CompoundPeriod(Minute(-1), Second(10)))\n        @test_throws DimensionError round(Float32, u\"m\", CompoundPeriod(Minute(-1), Second(10)), RoundDown)\n        @test_throws DimensionError round(Float32, u\"m\", CompoundPeriod(Minute(-1), Second(10)), digits=1)\n        @test_throws DimensionError round(Float32, u\"m\", CompoundPeriod(Minute(-1), Second(10)), RoundDown, sigdigits=3)\n        @test_throws DimensionError floor(Float32, u\"m\", CompoundPeriod(Minute(-1), Second(10)))\n        @test_throws DimensionError  ceil(Float32, u\"m\", CompoundPeriod(Minute(-1), Second(10)), digits=1)\n        @test_throws DimensionError trunc(Float32, u\"m\", CompoundPeriod(Minute(-1), Second(10)), sigdigits=3, base=2)\n\n        @test round(typeof(1.0f0u\"minute\"), Second(-50)) === -1.0f0u\"minute\"\n        @test round(typeof(1.0f0u\"minute\"), Second(50), RoundToZero) === 0.0f0u\"minute\"\n        @test round(typeof(1.0f0u\"wk\"), Day(10), digits=1) === 1.4f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), Day(10), sigdigits=3) === 1.43f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), Day(10), RoundUp, digits=1) === 1.5f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), Day(10), RoundDown, sigdigits=3) === 1.42f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), Day(10), RoundUp, digits=2, base=2) === 1.5f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), Day(10), RoundToZero, digits=2, base=2) === 1.25f0u\"wk\"\n        @test floor(typeof(1.0f0u\"wk\"), Day(10), sigdigits=3) === 1.42f0u\"wk\"\n        @test ceil(typeof(1.0f0u\"wk\"), Day(10), digits=2, base=2) === 1.5f0u\"wk\"\n        @test trunc(typeof(1.0f0u\"wk\"), Day(10), digits=2, base=2) === 1.25f0u\"wk\"\n        @test_throws DimensionError round(typeof(1.0u\"m\"), Second(1))\n        @test_throws DimensionError round(typeof(1.0u\"m\"), Second(1), RoundToZero)\n        @test_throws DimensionError round(typeof(1.0u\"m\"), Second(1), digits=1)\n        @test_throws DimensionError round(typeof(1.0u\"m\"), Second(1), RoundToZero, sigdigits=2)\n        @test_throws DimensionError floor(typeof(1.0u\"m\"), Second(1))\n        @test_throws DimensionError ceil(typeof(1.0u\"m\"), Second(1), sigdigits=2, base=2)\n        @test_throws DimensionError trunc(typeof(1.0u\"m\"), Second(1), digits=1)\n\n        @test round(typeof(1.0f0u\"minute\"), CompoundPeriod(Minute(-1), Second(10))) === -1.0f0u\"minute\"\n        @test round(typeof(1.0f0u\"minute\"), CompoundPeriod(Minute(1), Second(-10)), RoundToZero) === 0.0f0u\"minute\"\n        @test round(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), digits=1) === 1.4f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), sigdigits=3) === 1.43f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), RoundUp, digits=1) === 1.5f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), RoundDown, sigdigits=3) === 1.42f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), RoundUp, digits=2, base=2) === 1.5f0u\"wk\"\n        @test round(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), RoundToZero, digits=2, base=2) === 1.25f0u\"wk\"\n        @test floor(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), sigdigits=3) === 1.42f0u\"wk\"\n        @test ceil(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), digits=2, base=2) === 1.5f0u\"wk\"\n        @test trunc(typeof(1.0f0u\"wk\"), CompoundPeriod(Week(1), Day(3)), digits=2, base=2) === 1.25f0u\"wk\"\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Year(1)))\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Year(1)), RoundToZero)\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Year(1)), digits=1)\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Year(1)), RoundToZero, sigdigits=2)\n        @test_throws MethodError floor(typeof(1.0u\"s\"), CompoundPeriod(Year(1)))\n        @test_throws MethodError ceil(typeof(1.0u\"s\"), CompoundPeriod(Year(1)), sigdigits=2, base=2)\n        @test_throws MethodError trunc(typeof(1.0u\"s\"), CompoundPeriod(Year(1)), digits=1)\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Month(1)))\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Month(1)), RoundToZero)\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Month(1)), digits=1)\n        @test_throws MethodError round(typeof(1.0u\"s\"), CompoundPeriod(Month(1)), RoundToZero, sigdigits=2)\n        @test_throws MethodError floor(typeof(1.0u\"s\"), CompoundPeriod(Month(1)))\n        @test_throws MethodError ceil(typeof(1.0u\"s\"), CompoundPeriod(Month(1)), sigdigits=2, base=2)\n        @test_throws MethodError trunc(typeof(1.0u\"s\"), CompoundPeriod(Month(1)), digits=1)\n        @test_throws DimensionError round(typeof(1.0u\"m\"), CompoundPeriod(Second(1)))\n        @test_throws DimensionError round(typeof(1.0u\"m\"), CompoundPeriod(Second(1)), RoundToZero)\n        @test_throws DimensionError round(typeof(1.0u\"m\"), CompoundPeriod(Second(1)), digits=1)\n        @test_throws DimensionError round(typeof(1.0u\"m\"), CompoundPeriod(Second(1)), RoundToZero, sigdigits=2)\n        @test_throws DimensionError floor(typeof(1.0u\"m\"), CompoundPeriod(Second(1)))\n        @test_throws DimensionError  ceil(typeof(1.0u\"m\"), CompoundPeriod(Second(1)), sigdigits=2, base=2)\n        @test_throws DimensionError trunc(typeof(1.0u\"m\"), CompoundPeriod(Second(1)), digits=1)\n    end\n\n    @testset \"> Comparison\" begin\n        # ==\n        @test Second(2) == 2.0u\"s\"\n        @test 72u\"hr\" == Day(3)\n        @test Millisecond(0) == -0.0u\"ms\"\n        @test !(Day(4) == 4u\"hr\")\n        @test !(4u\"cm\" == Day(4))\n\n        @test CompoundPeriod(Day(365), Hour(6)) == 1u\"yr\"\n        @test 1u\"yr\" == CompoundPeriod(Day(365), Hour(6))\n        @test CompoundPeriod() == -0.0u\"s\"\n        @test !(1u\"m\" == CompoundPeriod(Day(1)))\n        @test !(CompoundPeriod(Day(1)) == 1u\"m\")\n        @test !(1u\"yr\" == CompoundPeriod(Year(1)))\n        @test !(1u\"yr\" == CompoundPeriod(Month(12)))\n        @test !(CompoundPeriod(Year(1)) == 1u\"yr\")\n        @test !(CompoundPeriod(Month(12)) == 1u\"yr\")\n\n        # isequal\n        @test isequal(Second(2), 2.0u\"s\")\n        @test isequal(72u\"hr\", Day(3))\n        @test !isequal(Millisecond(0), -0.0u\"ms\") # !isequal(0.0, -0.0)\n        @test !isequal(Day(4), 4u\"hr\")\n        @test !isequal(4u\"cm\", Day(4))\n\n        @test isequal(CompoundPeriod(), 0s)\n        @test isequal(CompoundPeriod(Day(365), Hour(6)), 1u\"yr\")\n        @test isequal(1u\"yr\", CompoundPeriod(Day(365), Hour(6)))\n        @test !isequal(CompoundPeriod(), -0.0u\"s\") # !isequal(0.0, -0.0)\n        @test !isequal(1u\"m\", CompoundPeriod(Day(1)))\n        @test !isequal(CompoundPeriod(Day(1)), 1u\"m\")\n        @test !isequal(1u\"yr\", CompoundPeriod(Year(1)))\n        @test !isequal(1u\"yr\", CompoundPeriod(Month(12)))\n        @test !isequal(CompoundPeriod(Year(1)), 1u\"yr\")\n        @test !isequal(CompoundPeriod(Month(12)), 1u\"yr\")\n\n        # hash\n        @test_broken hash(Second(2)) === hash(2.0s)\n        @test_broken hash(72hr) === hash(Day(3))\n        @test_broken hash(CompoundPeriod()) === hash(0s)\n        @test_broken hash(CompoundPeriod(Hour(6))) === hash(6hr)\n\n        # <\n        @test Second(1) < 1001u\"ms\"\n        @test 3u\"minute\" < Minute(4)\n        @test !(Minute(3) < 3u\"minute\")\n        @test !(7u\"d\" < Week(1))\n        @test !(-0.0u\"d\" < Day(0))\n        @test_throws DimensionError 7u\"kg\" < Day(1)\n        @test_throws DimensionError Day(1) < 7u\"kg\"\n\n        @test CompoundPeriod(Day(365)) < 1u\"yr\"\n        @test 1u\"s\" < CompoundPeriod(Second(1), Nanosecond(1))\n        @test !(CompoundPeriod(Day(365), Hour(6)) < 1u\"yr\")\n        @test !(1u\"s\" < CompoundPeriod(Second(1)))\n        @test !(-0.0u\"s\" < CompoundPeriod())\n        @test_throws DimensionError 7u\"kg\" < CompoundPeriod(Day(1))\n        @test_throws DimensionError CompoundPeriod() < 1u\"m\"\n        @test_throws MethodError 1u\"s\" < CompoundPeriod(Year(1))\n        @test_throws MethodError 1u\"s\" < CompoundPeriod(Month(1))\n        @test_throws MethodError CompoundPeriod(Year(1)) < 2u\"yr\"\n        @test_throws MethodError CompoundPeriod(Month(1)) < 1u\"yr\"\n\n        # isless\n        @test isless(Second(1), 1001u\"ms\")\n        @test isless(3u\"minute\", Minute(4))\n        @test !isless(Minute(3), 3u\"minute\")\n        @test !isless(7u\"d\", Week(1))\n        @test isless(-0.0u\"d\", Day(0))\n        @test_throws DimensionError isless(7u\"kg\", Day(1))\n        @test_throws DimensionError isless(Day(1), 7u\"kg\")\n\n        @test isless(CompoundPeriod(Day(365)), 1u\"yr\")\n        @test isless(1u\"s\", CompoundPeriod(Second(1), Nanosecond(1)))\n        @test !isless(CompoundPeriod(Day(365), Hour(6)), 1u\"yr\")\n        @test !isless(1u\"s\", CompoundPeriod(Second(1)))\n        @test isless(-0.0u\"s\", CompoundPeriod())\n        @test_throws DimensionError isless(7u\"kg\", CompoundPeriod(Day(1)))\n        @test_throws DimensionError isless(CompoundPeriod(), 1u\"m\")\n        @test_throws MethodError isless(1u\"s\", CompoundPeriod(Year(1)))\n        @test_throws MethodError isless(1u\"s\", CompoundPeriod(Month(1)))\n        @test_throws MethodError isless(CompoundPeriod(Year(1)), 2u\"yr\")\n        @test_throws MethodError isless(CompoundPeriod(Month(1)), 1u\"yr\")\n\n        # ≤\n        @test Second(1) ≤ 1001u\"ms\"\n        @test 7u\"d\" ≤ Week(1)\n        @test !(Minute(4) ≤ 3u\"minute\")\n        @test_throws DimensionError 7u\"kg\" ≤ Day(1)\n        @test_throws DimensionError Day(1) ≤ 7u\"kg\"\n\n        @test CompoundPeriod(Day(365), Hour(6)) ≤ 1u\"yr\"\n        @test 1u\"s\" ≤ CompoundPeriod(Second(1), Nanosecond(1))\n        @test !(1u\"s\" ≤ CompoundPeriod(Millisecond(999)))\n        @test_throws DimensionError 7u\"kg\" ≤ CompoundPeriod(Day(1))\n        @test_throws DimensionError CompoundPeriod() ≤ 1u\"m\"\n        @test_throws MethodError 1u\"s\" ≤ CompoundPeriod(Year(1))\n        @test_throws MethodError 1u\"s\" ≤ CompoundPeriod(Month(1))\n        @test_throws MethodError CompoundPeriod(Year(1)) ≤ 2u\"yr\"\n        @test_throws MethodError CompoundPeriod(Month(1)) ≤ 1u\"yr\"\n\n        # min, max\n        @test min(1u\"s\", Microsecond(100)) == Microsecond(100)\n        @test min(Day(1), 1u\"hr\") == 1u\"hr\"\n        @test_throws DimensionError min(1u\"kg\", Second(1))\n        @test_throws DimensionError min(Second(1), 1u\"kg\")\n        @test max(1u\"s\", Microsecond(100)) == 1u\"s\"\n        @test max(Day(1), 1u\"hr\") == Day(1)\n        @test_throws DimensionError max(1u\"kg\", Second(1))\n        @test_throws DimensionError max(Second(1), 1u\"kg\")\n\n        @test min(1u\"s\", CompoundPeriod()) == CompoundPeriod()\n        @test min(1u\"yr\", CompoundPeriod(Day(365), Hour(7))) == 1u\"yr\"\n        @test_throws DimensionError min(CompoundPeriod(), 1u\"m\")\n        @test_throws DimensionError min(1u\"m\", CompoundPeriod())\n        @test_throws MethodError min(1u\"yr\", CompoundPeriod(Year(1)))\n        @test_throws MethodError min(CompoundPeriod(Month(1)), 1u\"yr\")\n        @test max(1u\"s\", CompoundPeriod()) == 1u\"s\"\n        @test max(1u\"yr\", CompoundPeriod(Day(365), Hour(7))) == CompoundPeriod(Day(365), Hour(7))\n        @test_throws DimensionError max(CompoundPeriod(), 1u\"m\")\n        @test_throws DimensionError max(1u\"m\", CompoundPeriod())\n        @test_throws MethodError max(1u\"yr\", CompoundPeriod(Year(1)))\n        @test_throws MethodError max(CompoundPeriod(Month(1)), 1u\"yr\")\n    end\n\n    @testset \"> isapprox\" begin\n        # scalar arguments\n        @test isapprox(nextfloat(1.0)u\"s\", Second(1))\n        @test isapprox(1.0u\"s\", Second(1), rtol=0)\n        @test isapprox(Second(2), 2500u\"ms\", atol=1u\"s\")\n        @test isapprox(Second(2), 2500u\"ms\", atol=Second(1))\n        @test isapprox(2500u\"ms\", Second(2), rtol=0.5)\n        @test !isapprox(2500u\"ms\", Second(2), rtol=0.1)\n        @test !isapprox(nextfloat(1.0)u\"s\", Second(1), rtol=0)\n        @test !isapprox(Second(1), 1u\"m\")\n        @test !isapprox(1u\"m\", Second(1))\n        @test !isapprox(Second(1), 1u\"m\", atol=1u\"kg\")\n        @test !isapprox(1u\"m\", Second(1), atol=Second(1))\n        @test_throws DimensionError isapprox(Second(2), 2500u\"ms\", atol=0.5)\n        @test_throws DimensionError isapprox(Second(2), 2500u\"ms\", atol=0.5u\"m\")\n\n        @test isapprox(nextfloat(1.0)u\"yr\", CompoundPeriod(Day(365), Hour(6)))\n        @test isapprox(1.0u\"yr\", CompoundPeriod(Day(365), Hour(6)), rtol=0)\n        @test isapprox(2u\"s\", CompoundPeriod(Second(2), Millisecond(500)), atol=1u\"s\")\n        @test isapprox(CompoundPeriod(Second(2), Millisecond(500)), 2u\"s\", atol=CompoundPeriod(Second(1)))\n        @test isapprox(CompoundPeriod(Second(2), Millisecond(500)), 2u\"s\", rtol=0.5)\n        @test !isapprox(CompoundPeriod(Second(2), Millisecond(500)), 2u\"s\", rtol=0.1)\n        @test !isapprox(CompoundPeriod(Week(1), Nanosecond(1)), 1.0u\"wk\", rtol=0)\n        @test !isapprox(CompoundPeriod(Second(1)), 1u\"m\")\n        @test !isapprox(1u\"m\", CompoundPeriod(Second(1)))\n        @test !isapprox(CompoundPeriod(Second(1)), 1u\"m\", atol=1u\"kg\")\n        @test !isapprox(1u\"m\", CompoundPeriod(Second(1)), atol=CompoundPeriod(Second(1)))\n        @test_throws MethodError isapprox(CompoundPeriod(Year(1)), 1u\"s\")\n        @test_throws MethodError isapprox(1u\"s\", CompoundPeriod(Year(1)), rtol=1)\n        @test_throws MethodError isapprox(1u\"s\", 1u\"s\", atol=CompoundPeriod(Year(1)))\n        @test_throws MethodError isapprox(CompoundPeriod(Month(1)), 1u\"s\")\n        @test_throws MethodError isapprox(1u\"s\", CompoundPeriod(Month(1)), rtol=1)\n        @test_throws MethodError isapprox(1u\"s\", 1u\"s\", atol=CompoundPeriod(Month(1)))\n        @test_throws DimensionError isapprox(CompoundPeriod(Day(1)), 1u\"d\", atol=0.1)\n        @test_throws DimensionError isapprox(1u\"d\", CompoundPeriod(Day(1)), atol=0.1u\"m\")\n\n        # array arguments\n        @test isapprox([Second(-5), Second(5)], [-5.0u\"s\", 5.0u\"s\"])\n        @test isapprox([Second(-5), Second(5)], [-4.99u\"s\", 5.01u\"s\"], rtol=1e-2)\n        @test_broken isapprox([1u\"s\", 60u\"s\"], Period[Second(1), Minute(1)], rtol=0)\n        @test !isapprox([1.0u\"kg\"], [Second(1)])\n\n        @test isapprox([CompoundPeriod(Day(2), Hour(12)), CompoundPeriod(Day(-3), Hour(12))], [2.5u\"d\", -2.5u\"d\"])\n        @test isapprox([2.51u\"d\", -2.49u\"d\"], [CompoundPeriod(Day(2), Hour(12)), CompoundPeriod(Day(-3), Hour(12))], rtol=1e-2)\n        @test isapprox([1u\"s\", 60u\"s\"], CompoundPeriod[Second(1), Minute(1)], rtol=0)\n        @test !isapprox([CompoundPeriod(Day(1))], [1.0u\"kg\"])\n        @test_throws MethodError isapprox([CompoundPeriod(Year(1))], [1.0u\"yr\"])\n        @test_throws MethodError isapprox([1.0u\"yr\"], [CompoundPeriod(Month(12))], rtol=1)\n    end\n\n    @testset \"> promote\" begin\n        @test promote(1u\"d\", Minute(1)) === promote(1u\"d\", Int64(1)u\"minute\")\n        @test promote(Second(10), 2.0u\"fs\") === promote(Int64(10)u\"s\", 2.0u\"fs\")\n        @test_throws ErrorException promote(1u\"m\", Second(1))\n        @test_throws ErrorException promote(Day(1), 3u\"T\")\n    end\n\n    sleep(10u\"ms\")    # not tested explicitly, because sleep doesn't come with guarantees\nend\n"
  },
  {
    "path": "test/runtests.jl",
    "content": "using Unitful\nusing Test, LinearAlgebra, Random, ConstructionBase, InverseFunctions, Printf\nimport Unitful: DimensionError, AffineError\nimport Unitful: LogScaled, LogInfo, Level, Gain, MixedUnits, Decibel\nimport Unitful: FreeUnits, ContextUnits, FixedUnits, AffineUnits, AffineQuantity\nimport ForwardDiff\nimport NaNMath\nimport Latexify: Latexify, latexify, @latexify, FancyNumberFormatter, SiunitxNumberFormatter\nimport LaTeXStrings: LaTeXString, @L_str\n\nimport Unitful:\n    nm, μm, mm, cm, m, km, inch, ft, mi,\n    ac,\n    mg, g, kg,\n    Ra, °F, °C, K,\n    rad, mrad, °, deg,\n    ms, s, minute, hr, d, yr, Hz,\n    J, A, N, mol, V, mJ, eV, dyn, mN,\n    mW, W,\n    dB, dB_rp, dB_p, dBm, dBV, dBSPL, Decibel,\n    Np, Np_rp, Np_p, Neper,\n    C\n\nimport Unitful: 𝐋, 𝐓, 𝐍, 𝚯\n\nimport Unitful:\n    Length, Area, Volume,\n    Luminosity,\n    Time, Frequency,\n    Mass,\n    Current,\n    Temperature, AbsoluteScaleTemperature, RelativeScaleTemperature,\n    Action,\n    Power,\n    MassFlow,\n    MolarFlow,\n    VolumeFlow\n\nimport Unitful: LengthUnits, AreaUnits, MassUnits, TemperatureUnits\n\nusing Dates:\n    Dates,\n    Nanosecond, Microsecond, Millisecond, Second, Minute, Hour, Day, Week,\n    Month, Year,\n    CompoundPeriod\n\nconst colon = Base.:(:)\n\nmacro test_or_throws(extype, ex)\n    return :(\n        try\n            # if the first line throws, go to @test_throws in catch clause\n            # if not: test expression normally\n            result = $ex\n            @test result\n        catch\n            @test_throws $extype $ex\n        end\n    )\nend\n\nis_finite_nonzero(x) = isfinite(x) && !iszero(x)\n\n@testset \"Construction\" begin\n    @test isa(NoUnits, FreeUnits)\n    @test typeof(𝐋) === Unitful.Dimensions{(Unitful.Dimension{:Length}(1),)}\n    @test 𝐋*𝐋 === 𝐋^2\n    @test typeof(1.0m) === Unitful.Quantity{Float64, 𝐋,\n        Unitful.FreeUnits{(Unitful.Unit{:Meter, 𝐋}(0,1),), 𝐋, nothing}}\n    @test typeof(1m^2) === Unitful.Quantity{Int, 𝐋^2,\n            Unitful.FreeUnits{(Unitful.Unit{:Meter, 𝐋}(0,2),), 𝐋^2, nothing}}\n    @test typeof(1ac) === Unitful.Quantity{Int, 𝐋^2,\n            Unitful.FreeUnits{(Unitful.Unit{:Acre, 𝐋^2}(0,1),), 𝐋^2, nothing}}\n    @test typeof(ContextUnits(m,μm)) ===\n        ContextUnits{(Unitful.Unit{:Meter, 𝐋}(0,1),), 𝐋, typeof(μm), nothing}\n    @test typeof(1.0*ContextUnits(m,μm)) === Unitful.Quantity{Float64, 𝐋,\n        ContextUnits{(Unitful.Unit{:Meter, 𝐋}(0,1),), 𝐋, typeof(μm), nothing}}\n    @test typeof(1.0*FixedUnits(m)) === Unitful.Quantity{Float64, 𝐋,\n        FixedUnits{(Unitful.Unit{:Meter, 𝐋}(0,1),), 𝐋, nothing}}\n    @test 3mm != 3*(m*m)                        # mm not interpreted as m*m\n    @test (3+4im)*V === V*(3+4im) === (3V+4V*im)  # Complex quantity construction\n    @test !isreal(Base.complex(3.0/m, 4.0/m))\n    @test !isreal(Base.complex((3.0+4.0im)/m))\n    @test Base.reim(Base.complex((3.0+4.0im)/m)) == (3.0/m, 4.0/m)\n    @test Base.complex(1m, 1.5m) == Base.complex(1.0m, 1.5m)\n    @test Base.widen(Base.complex(Float32(3.0)/m)) == Base.complex(Float64(3.0)/m)\n    @test Base.complex(1.0/m) == (1.0/m + (0.0/m)*im)\n    @test Base.complex(1.0/m + (1.5/m)*im) == (1.0/m + (1.5/m)*im)\n    @test 3*NoUnits === 3\n    @test 3*(FreeUnits(m)/FreeUnits(m)) === 3\n    @test 3*(ContextUnits(m)/ContextUnits(m)) === 3\n    @test 3*(FixedUnits(m)/FixedUnits(m)) === 3\n    @test ContextUnits(mm) === ContextUnits(mm,m)\n    @test Quantity(3, NoUnits) === 3\n    @test FreeUnits(ContextUnits(mm,m)) === FreeUnits(mm)\n    @test FreeUnits(FixedUnits(mm)) === FreeUnits(mm)\n    @test isa(FreeUnits(m), FreeUnits)\n    @test isa(ContextUnits(m), ContextUnits)\n    @test isa(ContextUnits(m,mm), ContextUnits)\n    @test isa(FixedUnits(m), FixedUnits)\n    @test ContextUnits(m, FixedUnits(mm)) === ContextUnits(m, mm)\n    @test ContextUnits(m, ContextUnits(mm, mm)) === ContextUnits(m, mm)\n    @test_throws DimensionError ContextUnits(m,kg)\n    @test ConstructionBase.constructorof(typeof(1.0m))(2) === 2m\nend\n\n@testset \"inverse\" begin\n    InverseFunctions.test_inverse(Base.Fix1(ustrip, m), 2m)\n    InverseFunctions.test_inverse(Base.Fix1(ustrip, m), 2mm)\nend\n\n@testset \"Types\" begin\n    @test Base.complex(Quantity{Float64,NoDims,NoUnits}) ==\n        Quantity{Complex{Float64},NoDims,NoUnits}\nend\n\n# A number type for which the results of `real` and `float`\n# are not `<:Real` or `<:AbstractFloat`, respectively\nstruct NonReal <: Number\n    num::Int\nend\nBase.:*(x::NonReal, y::Float64) = x.num * y\nBase.real(x::NonReal) = x\nBase.float(x::NonReal) = x\n\n# A number type for which `real` and `float` throw an error\nstruct ErrReal <: Number\n    num::Int\nend\nBase.:*(x::ErrReal, y::Float64) = x.num * y\nBase.real(x::ErrReal) = error(\"real not defined\")\nBase.float(x::ErrReal) = error(\"float not defined\")\n\n# A number type for which `real` and `float` do not return a built-in type\nstruct MyFloat64 <: AbstractFloat\n    num::Float64\nend\nBase.:*(x::MyFloat64, y::Float64) = x.num * y\n# Base.real(x::MyFloat) = x\n# Base.float(x::MyFloat) = x\n\n@testset \"Conversion\" begin\n    @testset \"> Unitless ↔ unitful conversion\" begin\n        @test_throws DimensionError convert(typeof(3m), 1)\n        @test_throws DimensionError convert(Quantity{Float64, typeof(𝐋)}, 1)\n        @test_throws DimensionError convert(Float64, 3m)\n        @test @inferred(3m/unit(3m)) === 3\n        @test @inferred(3.0g/unit(3.0g)) === 3.0\n        # 1-arg ustrip\n        @test @inferred(ustrip(3*FreeUnits(m))) === 3\n        @test @inferred(ustrip(3*ContextUnits(m,μm))) === 3\n        @test @inferred(ustrip(3*FixedUnits(m))) === 3\n        @test @inferred(ustrip(3)) === 3\n        @test @inferred(ustrip(3.0m)) === 3.0\n        # ustrip with type and unit arguments\n        @test @inferred(ustrip(m, 3.0m)) === 3.0\n        @test @inferred(ustrip(m, 2mm)) === 1//500\n        @test @inferred(ustrip(mm, 3.0m)) === 3000.0\n        @test @inferred(ustrip(NoUnits, 3.0m/1.0m)) === 3.0\n        @test @inferred(ustrip(NoUnits, 3.0m/1.0cm)) === 300.0\n        @test @inferred(ustrip(cm, missing)) === missing\n        @test @inferred(ustrip(NoUnits, missing)) === missing\n        @test_throws DimensionError ustrip(NoUnits, 3.0m/1.0s)\n        @test @inferred(ustrip(Float64, m, 2mm)) === 0.002\n        @test @inferred(ustrip(Int, mm, 2.0m)) === 2000\n        @test @inferred(ustrip(Float32, NoUnits, 5.0u\"m\"/2.0u\"m\")) === Float32(2.5)\n        @test @inferred(ustrip(Int, NoUnits, 3.0u\"m\"/1.0u\"cm\")) === 300\n        # convert\n        @test convert(typeof(1mm/m), 3) == 3000mm/m\n        @test convert(typeof(1mm/m), 3*NoUnits) == 3000mm/m\n        @test convert(typeof(1*ContextUnits(mm/m, NoUnits)), 3) == 3000mm/m\n        @test convert(typeof(1*FixedUnits(mm/m)), 3) == 3000*FixedUnits(mm/m)\n        @test convert(Int, 1*FreeUnits(m/mm)) === 1000\n        @test convert(Int, 1*FixedUnits(m/mm)) === 1000\n        @test convert(Int, 1*ContextUnits(m/mm, NoUnits)) === 1000\n        for U = (NoUnits, FixedUnits(NoUnits), ContextUnits(NoUnits, m/mm))\n            @test convert(Quantity{Int,NoDims,typeof(U)}, 1*FreeUnits(m/mm)) === Quantity{Int,NoDims,typeof(U)}(1000)\n            @test convert(Quantity{Int,NoDims,typeof(U)}, 1*FixedUnits(m/mm)) === Quantity{Int,NoDims,typeof(U)}(1000)\n            @test convert(Quantity{Int,NoDims,typeof(U)}, 1*ContextUnits(m/mm, NoUnits)) === Quantity{Int,NoDims,typeof(U)}(1000)\n            @test convert(Quantity{Int,NoDims,typeof(U)}, 1) === Quantity{Int,NoDims,typeof(U)}(1)\n        end\n        @test convert(Quantity{Int}, 1) === Quantity{Int,NoDims,typeof(NoUnits)}(1)\n        @test convert(Quantity{Int,NoDims}, 1) === Quantity{Int,NoDims,typeof(NoUnits)}(1)\n\n        # w/ units distinct from w/o units\n        @test 1m != 1\n        @test 1 != 1m\n        @test (3V+4V*im) != (3+4im)\n\n        # Issue 26\n        @unit altL \"altL\" altLiter 1000*cm^3 true\n        @test convert(Float64, 1altL/cm^3) === 1000.0\n        # Issue 327\n        @test uconvert(u\"√cm\", 1u\"√m\") == 10u\"√cm\"\n    end\n    @testset \"> Unitful ↔ unitful conversion\" begin\n        @testset \">> Numeric conversion\" begin\n            @test @inferred(float(3m)) === 3.0m\n            @test @inferred(Float32(3m)) === 3.0f0m\n            @test @inferred(Integer(3.0A)) === 3A\n            @test Rational(3.0m) === (Int64(3)//1)*m\n            @test typeof(convert(typeof(0.0°), 90°)) == typeof(0.0°)\n            @test (3.0+4.0im)*V == (3+4im)*V\n            @test im*V == Complex(0,1)*V\n            for x = (3, 3.0, 3//1, 1+2im, 1.0+2.0im, (1//2)+(3//4)im)\n                for u = (m, °C)\n                    @test @inferred(big(x*u)) == big(x)*u\n                    @test typeof(big(x*u)) == typeof(big(x)*u)\n                    @test big(typeof(x*u)) == typeof(big(x)*u)\n                end\n                q = Quantity{typeof(x),NoDims,typeof(NoUnits)}(x)\n                big_q = Quantity{big(typeof(x)),NoDims,typeof(NoUnits)}(big(x))\n                @test @inferred(big(q)) == big_q\n                @test typeof(big(q)) == typeof(big_q)\n                @test big(typeof(q)) == typeof(big_q)\n            end\n        end\n        @testset \">> Intra-unit conversion\" begin\n            # an essentially no-op uconvert should not disturb numeric type\n            @test @inferred(uconvert(g,1g)) === 1g\n            @test @inferred(uconvert(m,0x01*m)) === 0x01*m\n            @test @inferred(convert(Quantity{Float64, 𝐋}, 1m)) === 1.0m\n            @test 1kg === 1kg\n            @test typeof(1m)(1m) === 1m\n\n            @test 1*FreeUnits(kg) == 1*ContextUnits(kg,g)\n            @test 1*ContextUnits(kg,g) == 1*FreeUnits(kg)\n\n            @test 1*FreeUnits(kg) == 1*FixedUnits(kg)\n            @test 1*FixedUnits(kg) == 1*FreeUnits(kg)\n\n            @test 1*ContextUnits(kg,g) == 1*FixedUnits(kg)\n            @test 1*FixedUnits(kg) == 1*ContextUnits(kg,g)\n\n            # No auto conversion when working with FixedUnits exclusively.\n            @test_throws ErrorException 1*FixedUnits(kg) == 1000*FixedUnits(g)\n        end\n        @testset \">> Inter-unit conversion\" begin\n            @test 1g == 0.001kg                   # Issue 56\n            @test 0.001kg == 1g                   # Issue 56\n            @test 1kg == 1000g\n            @test !(1kg === 1000g)\n            @test 1inch == (254//100)*cm\n            @test 1ft == 12inch\n            @test 1/mi == 1//(5280ft)\n            @test 1minute == 60s\n            @test 1hr == 60minute\n            @test 1d == 24hr\n            @test 1yr == 365.25d\n            @test 1J == 1kg*m^2/s^2\n            @test typeof(1cm)(1m) === 100cm\n            @test (3V+4V*im) != (3m+4m*im)\n            @test_throws DimensionError uconvert(m, 1kg)\n            @test_throws DimensionError uconvert(m, 1*ContextUnits(kg,g))\n            @test_throws DimensionError uconvert(ContextUnits(m,mm), 1kg)\n            @test_throws DimensionError uconvert(m, 1*FixedUnits(kg))\n            @test uconvert(g, 1*FixedUnits(kg)) == 1000g         # manual conversion okay\n            @test (1kg, 2g, 3mg, missing) .|> g === (1000g, 2g, (3//1000)g, missing)\n            # Issue 79:\n            @test isapprox(upreferred(Unitful.ε0), 8.85e-12u\"F/m\", atol=0.01e-12u\"F/m\")\n            # Issue 261:\n            @test 1u\"rps\" == 360°/s\n            @test 1u\"rps\" == 2π/s\n            @test 1u\"rpm\" == 360°/minute\n            @test 1u\"rpm\" == 2π/minute\n            # Issue 430:\n            # definition for arcsecond taken from UnitfulAngles.jl\n            # definition for Jy arcsecond taken from UnitfulAstro.jl\n            @unit angles_arcsecond \"angles_″\" angles_Arcsecond °//3600 false\n            @unit astro_Jy \"astro_Jy\" astro_Jansky 1e-23u\"erg*s^-1*cm^-2*Hz^-1\" true\n            @test uconvert(\n                astro_Jy / angles_arcsecond^2, 1.0u\"GHz^2 * J * c^-2\"\n            ) ≈ 2.6152205956835644e16 * astro_Jy * angles_arcsecond^-2\n            # Issue 458:\n            @test deg2rad(360°) ≈ 2π * rad\n            @test rad2deg(2π * rad) ≈ 360°\n            # Issue 647:\n            @test uconvert(u\"kb^1000\", 1u\"kb^1001 * b^-1\") === 1000u\"kb^1000\"\n            @test uconvert(u\"kOe^1000\", 1u\"kOe^1001 * Oe^-1\") === 1000u\"kOe^1000\"\n            # Issue 753:\n            # preserve the floating point precision of quantities\n            for T = [Float16, Float32, Float64, BigFloat]\n                @test Unitful.numtype(uconvert(m, T(100)cm)) === T\n                @test Unitful.numtype(uconvert(cm, (T(1)π + im) * m)) === Complex{T}\n                @test Unitful.numtype(uconvert(rad, T(360)°)) === T\n                @test Unitful.numtype(uconvert(°, (T(2)π + im) * rad)) === Complex{T}\n                @test typeof(upreferred(T(360)°)) === T\n            end\n            @test uconvert(rad, NonReal(360)°) == uconvert(rad, 360°)\n            @test uconvert(rad, ErrReal(360)°) == uconvert(rad, 360°)\n            @test uconvert(rad, MyFloat64(360)°) == uconvert(rad, 360°)\n            @test upreferred(NonReal(360)°) == upreferred(360°)\n            @test upreferred(ErrReal(360)°) == upreferred(360°)\n            @test upreferred(MyFloat64(360)°) == upreferred(360°)\n            # Floating point overflow/underflow in uconvert can happen if the\n            # conversion factor is large, because uconvert does not cancel\n            # common basefactors (or just for really large exponents and/or\n            # SI prefixes). This test makes sure that uconvert does not silently\n            # return NaN, Inf, or 0 in these cases, i.e. either returns a finite\n            # result or throws an error indicating that it cannot handle the\n            # conversion.\n            @test_or_throws ArgumentError is_finite_nonzero(uconvert(u\"kb^12\", 1u\"b^12\"))\n            @test_or_throws ArgumentError is_finite_nonzero(uconvert(u\"ab^11\", 1u\"Tb^11\"))\n            @test_or_throws ArgumentError is_finite_nonzero(uconvert(u\"Tb^11\", 1u\"ab^11\"))\n            @test_or_throws ArgumentError is_finite_nonzero(uconvert(u\"b^11 * eV\", 1u\"m^22 * J\"))\n            @test_or_throws ArgumentError is_finite_nonzero(uconvert(u\"m^22 * J\", 1u\"b^11 * eV\"))\n            # min/max had code doing the equivalent of uconvert, and suffering\n            # from similar problems as issue 647 (see above)\n            @test_or_throws ArgumentError max(1u\"Ym^18\", 1u\"Em^18\") === 1u\"Ym^18\"\n            @test_or_throws ArgumentError max(1u\"Em^18\", 1u\"Ym^18\") === 1u\"Ym^18\"\n            @test_or_throws ArgumentError min(1u\"Ym^18\", 1u\"Em^18\") === 1u\"Em^18\"\n            @test_or_throws ArgumentError min(1u\"Em^18\", 1u\"Ym^18\") === 1u\"Em^18\"\n            @test_or_throws ArgumentError minmax(1u\"Ym^18\", 1u\"Em^18\") ===\n                (1u\"Em^18\", 1u\"Em^18\")\n            @test_or_throws ArgumentError max(1u\"fb^8\", 1u\"ab^8\") === 1u\"fb^8\"\n            @test_or_throws ArgumentError max(1u\"ab^8\", 1u\"fb^8\") === 1u\"fb^8\"\n            @test_or_throws ArgumentError min(1u\"fb^8\", 1u\"ab^8\") === 1u\"ab^8\"\n            @test_or_throws ArgumentError min(1u\"ab^8\", 1u\"fb^8\") === 1u\"ab^8\"\n            @test_or_throws ArgumentError minmax(1u\"fb^8\", 1u\"ab^8\") ===\n                (1u\"ab^8\", 1u\"fb^8\")\n            # Issue 660:\n            @test uconvert(u\"Å * ps^-2\", 1.0u\"kcal*Å^-1*g^-1\") ≈ 418.4u\"Å * ps^-2\"\n            # Issue 780:\n            @unit Fr      \"Fr\"      franklin 1sqrt(dyn)*cm false\n            @unit Test780 \"Test780\" test780  1sqrt(mN)*cm  false\n            @test uconvert(dyn, 1Fr^2/cm^2) ≈ 1dyn\n            @test uconvert(mN, 1Test780^2/cm^2) ≈ 1mN\n            @test_broken uconvert(dyn, 1Fr^2/cm^2) === 1dyn\n            @test_broken uconvert(mN, 1Test780^2/cm^2) === 1mN\n        end\n    end\nend\n\ninclude(\"dates.jl\")\n\n@testset \"Temperature and affine quantities\" begin\n    @testset \"Affine transforms and quantities\" begin\n        @test 1°C isa RelativeScaleTemperature\n        @test !isa(1°C, AbsoluteScaleTemperature)\n        @test 1K isa AbsoluteScaleTemperature\n        @test !isa(1K, RelativeScaleTemperature)\n\n        @test_throws AffineError °C*°C\n        @test_throws AffineError °C*K\n        @test_throws AffineError (0°C)*(0°C)\n        @test_throws AffineError (1°C)/(1°C)\n        @test_throws AffineError °C^2\n        let x = 2\n            @test_throws AffineError °C^x\n        end\n        @test_throws AffineError inv(°C)\n        @test_throws AffineError inv(0°C)\n        @test_throws AffineError sqrt(°C)\n        @test_throws AffineError sqrt(0°C)\n        @test_throws AffineError cbrt(°C)\n        @test_throws AffineError cbrt(0°C)\n        @test_throws AffineError 32°F + 1°F\n        @test_throws AffineError (32°F) * 2\n        @test_throws AffineError 2 * (32°F)\n        @test_throws AffineError (32°F) / 2\n        @test_throws AffineError 2 / (32°F)\n\n        for f = (:div, :rem, :divrem)\n            @eval for r = (RoundNearest, RoundNearestTiesAway, RoundNearestTiesUp,\n                           RoundToZero, RoundUp, RoundDown)\n                @test_throws AffineError $f(32°F, 2°F, r)\n                @test_throws AffineError $f(32°F, 2K, r)\n                @test_throws AffineError $f(32K, 2°F, r)\n            end\n        end\n        for f = (:div, :cld, :fld, :rem, :mod, :divrem, :fldmod)\n            @eval begin\n                @test_throws AffineError $f(32°F, 2°F)\n                @test_throws AffineError $f(32°F, 2K)\n                @test_throws AffineError $f(32K, 2°F)\n            end\n        end\n\n        @test zero(100°C) === 0K\n        @test zero(typeof(100°C)) === 0K\n        @test oneunit(100°C) === 1K\n        @test oneunit(typeof(100°C)) === 1K\n        @test_throws AffineError one(100°C)\n        @test_throws AffineError one(typeof(100°C))\n\n        @test 0°C isa AffineQuantity{T, 𝚯} where T    # is \"relative temperature\"\n        @test 0°C isa Temperature                             # dimensional correctness\n        @test °C isa AffineUnits{N, 𝚯} where N\n        @test °C isa TemperatureUnits\n\n        @test @inferred(uconvert(°F, 0°C))  === (32//1)°F   # Some known conversions...\n        @test @inferred(uconvert(°C, 32°F)) === (0//1)°C    #  ⋮\n        @test @inferred(uconvert(°C, 212°F)) === (100//1)°C #  ⋮\n        @test @inferred(uconvert(°C, 0x01*°C)) === 0x01*°C  # Preserve numeric type\n\n        # The next test is a little funky but checks the `affineunit` functionality\n        @test @inferred(uconvert(°F,\n            0*Unitful.affineunit(27315K//100 + 5K//9))) === (33//1)°F\n    end\n    @testset \"Temperature differences\" begin\n        @test @inferred(uconvert(Ra, 0K)) === 0Ra//1\n        @test @inferred(uconvert(K, 1Ra)) === 5K//9\n        @test @inferred(uconvert(μm/(m*Ra), 9μm/(m*K))) === 5μm/(m*Ra)//1\n\n        @test @inferred(uconvert(FreeUnits(Ra), 4.2K)) ≈ 7.56Ra\n        @test @inferred(unit(uconvert(FreeUnits(Ra), 4.2K))) === FreeUnits(Ra)\n        @test @inferred(uconvert(FreeUnits(Ra), 4.2*ContextUnits(K))) ≈ 7.56Ra\n        @test @inferred(unit(uconvert(FreeUnits(Ra), 4.2*ContextUnits(K)))) === FreeUnits(Ra)\n        @test @inferred(unit(uconvert(ContextUnits(Ra), 4.2K))) === ContextUnits(Ra)\n\n        let cc = ContextUnits(°C, °C), kc = ContextUnits(K, °C), rac = ContextUnits(Ra, °C)\n            @test 100°C + 1K === (7483//20)K\n            @test 100cc + 1K === (101//1)cc\n            @test 100cc + 1K == (101//1)°C\n            @test 1K + 100cc === (101//1)cc\n            @test 1K + 100cc == (101//1)°C\n            @test 100°C + 1Ra === (67267//180)K\n            @test 100°C - 212°F === (0//1)K\n            @test 100°C - 211°F === (5//9)K\n            @test 100°C - 1°C === 99K\n            @test 100°C - 32°F === (100//1)K\n            @test 10cc + 2.0K/hr * 60minute + 3.0K/hr * 60minute === 15.0cc\n            @test 10cc + 5kc === (15//1)cc\n            @test 10°C + 5kc === (15//1)cc\n            @test 10°C + (9//5)rac === (11//1)cc\n        end\n    end\n    @testset \"Promotion\" begin\n        @test_throws ErrorException Unitful.preferunits(°C)\n        @test @inferred(eltype([1°C, 1K])) <: Quantity{Rational{Int}, 𝚯, typeof(K)}\n        @test @inferred(eltype([1.0°C, 1K])) <: Quantity{Float64, 𝚯, typeof(K)}\n        @test @inferred(eltype([1°C, 1°F])) <: Quantity{Rational{Int}, 𝚯, typeof(K)}\n        @test @inferred(eltype([1.0°C, 1°F])) <: Quantity{Float64, 𝚯, typeof(K)}\n\n        # context units should be identifiable as affine\n        @test ContextUnits(°C, °F) isa AffineUnits\n\n        let fc = ContextUnits(°F, °C), cc = ContextUnits(°C, °C)\n            @test @inferred(promote(1fc, 1cc)) === ((-155//9)cc, (1//1)cc)\n            @test @inferred(eltype([1cc, 1°C])) <: Quantity{Rational{Int}, 𝚯, typeof(cc)}\n        end\n    end\nend\n\n# preferred units work on AbstractQuantity\nstruct QQQ <: Unitful.AbstractQuantity{Float64,𝐋,typeof(cm)}\n    val::Float64\nend\nUnitful.uconvert(U::Unitful.Units, q::QQQ) = uconvert(U, Quantity(q.val, cm))\n\n@testset \"Promotion\" begin\n    @testset \"> Unit preferences\" begin\n        # Should warn on possible redundant units issue (ms and s)\n        @test_logs (:warn, r\"^Preferred units contain complex units\") Unitful.preferunits(C/ms)\n        # Test for wacky preferred units functionality\n        Unitful.preferunits(C/s)\n        @test @inferred(upreferred(V/m)) == kg*m*C^-1*s^-2\n        @test dimension(upreferred(V/m)) == dimension(V/m)\n        # Reset preferred units to default, except for units of dimension 𝐋*𝐌*𝐈^-1*𝐓^-3,\n        # because upreferred has already been called for that dimension\n        Unitful.preferunits(A)\n\n        # Only because we favor SI, we have the following:\n        @test @inferred(upreferred(N)) === kg*m/s^2\n        @test @inferred(upreferred(dimension(N))) === kg*m/s^2\n        @test @inferred(upreferred(g)) === kg\n        @test @inferred(upreferred(FreeUnits(g))) === FreeUnits(kg)\n\n        # Test special units behaviors\n        @test @inferred(upreferred(ContextUnits(g,mg))) === ContextUnits(mg,mg)\n        @test @inferred(upreferred(FixedUnits(kg))) === FixedUnits(kg)\n        @test @inferred(upreferred(upreferred(1.0ContextUnits(kg,g)))) ===\n            1000.0ContextUnits(g,g)\n        @test @inferred(upreferred(unit(1g |> ContextUnits(g,mg)))) === ContextUnits(mg,mg)\n        @test @inferred(upreferred(1g |> ContextUnits(g,mg))) == 1000mg\n\n        @test @inferred(upreferred(1N)) === 1*kg*m/s^2\n        @test ismissing(upreferred(missing))\n\n        # preferred units work on AbstractQuantity\n        @test @inferred(upreferred(QQQ(10))) == 0.1m\n    end\n    @testset \"> promote_unit\" begin\n        @test Unitful.promote_unit(FreeUnits(m)) === FreeUnits(m)\n        @test Unitful.promote_unit(ContextUnits(m,mm)) === ContextUnits(m,mm)\n        @test Unitful.promote_unit(FixedUnits(kg)) === FixedUnits(kg)\n        @test Unitful.promote_unit(ContextUnits(m,mm), ContextUnits(km,mm)) ===\n            ContextUnits(mm,mm)\n        @test Unitful.promote_unit(FreeUnits(m), ContextUnits(mm,km)) ===\n            ContextUnits(km,km)\n        @test Unitful.promote_unit(FixedUnits(kg), ContextUnits(g,g)) === FixedUnits(kg)\n        @test Unitful.promote_unit(ContextUnits(g,g), FixedUnits(kg)) === FixedUnits(kg)\n        @test Unitful.promote_unit(FixedUnits(kg), FreeUnits(g)) === FixedUnits(kg)\n        @test Unitful.promote_unit(FreeUnits(g), FixedUnits(kg)) === FixedUnits(kg)\n        @test_throws DimensionError Unitful.promote_unit(m,kg)\n\n        # FixedUnits throw a promotion error\n        @test_throws ErrorException Unitful.promote_unit(FixedUnits(m), FixedUnits(mm))\n\n        # Only because we favor SI, we have the following:\n        @test Unitful.promote_unit(m,km) === m\n        @test Unitful.promote_unit(m,km,cm) === m\n        @test Unitful.promote_unit(ContextUnits(m,mm), ContextUnits(km,cm)) ===\n            FreeUnits(m)\n    end\n    @testset \"> Simple promotion\" begin\n        # promotion should do nothing to units alone\n        # promote throws an error if no types are be changed\n        @test_throws ErrorException promote(m, km)\n        @test_throws ErrorException promote(ContextUnits(m, km), ContextUnits(mm, km))\n        @test_throws ErrorException promote(FixedUnits(m), FixedUnits(km))\n\n        # promote the numeric type\n        @test @inferred(promote(1.0m, 1m)) === (1.0m, 1.0m)\n        @test @inferred(promote(1m, 1.0m)) === (1.0m, 1.0m)\n        @test @inferred(promote(1.0g, 1kg)) === (0.001kg, 1.0kg)\n        @test @inferred(promote(1g, 1.0kg)) === (0.001kg, 1.0kg)\n        @test @inferred(promote(1.0m, 1kg)) === (1.0m, 1.0kg)\n        @test @inferred(promote(1kg, 1.0m)) === (1.0kg, 1.0m)\n        @test_broken @inferred(promote(1.0m, 1)) === (1.0m, 1.0)         # issue 52\n        @test @inferred(promote(π, 180°)) === (float(π), float(π))       # issue 168\n        @test @inferred(promote(180°, π)) === (float(π), float(π))       # issue 168\n\n        # prefer no units for dimensionless numbers\n        @test @inferred(promote(1.0mm/m, 1.0km/m)) === (0.001,1000.0)\n        @test @inferred(promote(1.0cm/m, 1.0mm/m, 1.0km/m)) === (0.01,0.001,1000.0)\n        @test @inferred(promote(1.0rad,1.0°)) === (1.0,π/180.0)\n\n        # Quantities with promotion context\n        # Context overrides free units\n        nm2μm = ContextUnits(nm,μm)\n        μm2μm = ContextUnits(μm,μm)\n        μm2mm = ContextUnits(μm,mm)\n        @test @inferred(promote(1.0nm2μm, 1.0m)) === (0.001μm2μm, 1e6μm2μm)\n        @test @inferred(promote(1.0m, 1.0μm2μm)) === (1e6μm2μm, 1.0μm2μm)\n        @test ===(upreferred.(unit.(promote(1.0nm2μm, 2nm2μm)))[1], ContextUnits(μm,μm))\n        @test ===(upreferred.(unit.(promote(1.0nm2μm, 2nm2μm)))[2], ContextUnits(μm,μm))\n\n        # Context agreement\n        @test @inferred(promote(1.0nm2μm, 1.0μm2μm)) ===\n            (0.001μm2μm, 1.0μm2μm)\n        @test @inferred(promote(1μm2μm, 1.0nm2μm, 1.0m)) ===\n            (1.0μm2μm, 0.001μm2μm, 1e6μm2μm)\n        @test @inferred(promote(1μm2μm, 1.0nm2μm, 1.0s)) ===\n            (1.0μm2μm, 1.0nm2μm, 1.0s)\n        # Context disagreement: fall back to free units\n        @test @inferred(promote(1.0nm2μm, 1.0μm2mm)) === (1e-9m, 1e-6m)\n    end\n    @testset \"> Promotion during array creation\" begin\n        @test typeof([1.0m,1.0m]) == Array{typeof(1.0m),1}\n        @test typeof([1.0m,1m]) == Array{typeof(1.0m),1}\n        @test typeof([1.0m,1cm]) == Array{typeof(1.0m),1}\n        @test typeof([1kg,1g]) == Array{typeof(1kg//1),1}\n        @test typeof([1.0m,1]) == Array{Quantity{Float64},1}\n        @test typeof([1.0m,1kg]) == Array{Quantity{Float64},1}\n        @test typeof([1.0m/s 1; 1 0]) == Array{Quantity{Float64},2}\n    end\n    @testset \"> Issue 52\" begin\n        x,y = 10m, 1\n        px,py = promote(x,y)\n\n        # promoting the second time should not change the types\n        @test_throws ErrorException promote(px, py)\n    end\n    @testset \"> Some internal behaviors\" begin\n        # quantities\n        @test Unitful.numtype(Quantity{Float64}) <: Float64\n        @test Unitful.numtype(Quantity{Float64, 𝐋}) <: Float64\n        @test Unitful.numtype(typeof(1.0kg)) <: Float64\n        @test Unitful.numtype(1.0kg) <: Float64\n    end\nend\n\n@testset \"Hashing\" begin\n    @test hash(big(1.0)m) === hash(big(1.0)m)\n    @test hash(1.0m) === hash(1m)\n    @test hash(0.5m) === hash((1//2)m)\n    @test hash(2.0m) === hash(2.0ContextUnits(m, cm))\n    @test hash(3.0m) === hash(3.0FixedUnits(m))\n    @test_broken hash(0.5m) === hash(500mm)\n    @test_broken hash(1rad) === hash(1)\nend\n\n@testset \"Unit string parsing\" begin\n    @test uparse(\"m\") == m\n    @test uparse(\"m,s\") == (m,s)\n    @test uparse(\"1.0\") == 1.0\n    @test uparse(\"m/s\") == m/s\n    @test uparse(\"N*m\") == N*m\n    @test uparse(\"1.0m/s\") == 1.0m/s\n    @test uparse(\"m^-1\") == m^-1\n    @test uparse(\"dB/Hz\") == dB/Hz\n    @test uparse(\"3.0dB/Hz\") == 3.0dB/Hz\n\n    # Invalid unit strings\n    @test_throws Meta.ParseError uparse(\"N m\")\n    @test_throws ArgumentError uparse(\"abs(2)\")\n    @test_throws ArgumentError uparse(\"(1,2)\")\n    @test_throws ArgumentError uparse(\"begin end\")\n\n    # test ustrcheck_bool\n    @test_throws ArgumentError uparse(\"basefactor\") # non-Unit symbols\n    # ustrcheck_bool(::Quantity)\n    @test uparse(\"h\") == Unitful.h\n    @test uparse(\"π\") == π              # issue 112\nend\n\n@testset \"Unit and dimensional analysis\" begin\n    @test @inferred(unit(1m^2)) === m^2\n    @test @inferred(unit(typeof(1m^2))) === m^2\n    @test @inferred(unit(Float64)) === NoUnits\n    @test @inferred(unit(Union{typeof(1m^2),Missing})) === m^2\n    @test @inferred(unit(Union{Float64,Missing})) === NoUnits\n    @test @inferred(unit(missing)) === missing\n    @test @inferred(unit(Missing)) === missing\n    @test @inferred(dimension(1m^2)) === 𝐋^2\n    @test @inferred(dimension(1*ContextUnits(m,km)^2)) === 𝐋^2\n    @test @inferred(dimension(typeof(1m^2))) === 𝐋^2\n    @test @inferred(dimension(Float64)) === NoDims\n    @test @inferred(dimension(m^2)) === 𝐋^2\n    @test @inferred(dimension(1m/s)) === 𝐋/𝐓\n    @test @inferred(dimension(m/s)) === 𝐋/𝐓\n    @test @inferred(dimension(1u\"mol\")) === 𝐍\n    @test @inferred(dimension(μm/m)) === NoDims\n    @test @inferred(dimension(missing)) === missing\n    @test @inferred(dimension(Missing)) === missing\n    @test dimension.([1u\"m\", 1u\"s\"]) == [𝐋, 𝐓]\n    @test dimension.([u\"m\", u\"s\"]) == [𝐋, 𝐓]\n    @test (𝐋/𝐓)^2 === 𝐋^2 / 𝐓^2\n    @test isa(m, LengthUnits)\n    @test isa(ContextUnits(m,km), LengthUnits)\n    @test isa(FixedUnits(m), LengthUnits)\n    @test !isa(m, AreaUnits)\n    @test !isa(ContextUnits(m,km), AreaUnits)\n    @test !isa(FixedUnits(m), AreaUnits)\n    @test !isa(m, MassUnits)\n    @test isa(m^2, AreaUnits)\n    @test !isa(m^2, LengthUnits)\n    @test isa(1m, Length)\n    @test isa(1*ContextUnits(m,km), Length)\n    @test isa(1*FixedUnits(m), Length)\n    @test !isa(1m, LengthUnits)\n    @test !isa(1m, Area)\n    @test !isa(1m, Luminosity)\n    @test isa(1ft, Length)\n    @test isa(1m^2, Area)\n    @test !isa(1m^2, Length)\n    @test isa(1inch^3, Volume)\n    @test isa(1/s, Frequency)\n    @test isa(1kg, Mass)\n    @test isa(1s, Time)\n    @test isa(1A, Current)\n    @test isa(1K, Temperature)\n    @test isa(1u\"cd\", Luminosity)\n    @test isa(2π*rad*1.0m, Length)\n    @test isa(u\"h\", Action)\n    @test isa(3u\"dBm\", Power)\n    @test isa(3u\"dBm*Hz*s\", Power)\n    @test isa(1kg/s, MassFlow)\n    @test isa(1mol/s, MolarFlow)\n    @test isa(1m^3/s, VolumeFlow)\nend\n\n# A number type with non-commutative multiplication\nstruct MatNum <: Number\n    mat::Matrix{Int}\nend\nBase.:(==)(x::MatNum, y::MatNum) = x.mat == y.mat\nBase.:*(x::MatNum, y::MatNum) = MatNum(x.mat*y.mat)\n\n# A number type that defines only `<=`, not `==` or `<`\nstruct Issue399 <: Integer\n    num::Int\nend\nBase.:<(::Issue399, ::Issue399) = error(\"< not defined\")\nBase.:(==)(::Issue399, ::Issue399) = error(\"== not defined\")\nBase.:(<=)(x::Issue399, y::Issue399) = x.num <= y.num\n\n@testset \"Mathematics\" begin\n    @testset \"> Comparisons\" begin\n        # make sure we are just picking one of the arguments, without surprising conversions\n        # happening to the units...\n        @test min(1FreeUnits(hr), 1FreeUnits(s)) === 1FreeUnits(s)\n        @test min(1FreeUnits(hr), 1ContextUnits(s,ms)) === 1ContextUnits(s,ms)\n        @test min(1ContextUnits(s,ms), 1FreeUnits(hr)) === 1ContextUnits(s,ms)\n        @test min(1ContextUnits(s,minute), 1ContextUnits(hr,s)) ===\n            1ContextUnits(s,minute)\n        @test max(1ContextUnits(ft, mi), 1ContextUnits(m,mm)) ===\n            1ContextUnits(m,mm)\n        @test min(1FreeUnits(hr), 1FixedUnits(s)) === 1FixedUnits(s)\n        @test min(1FixedUnits(s), 1FreeUnits(hr)) === 1FixedUnits(s)\n        @test min(1FixedUnits(s), 1ContextUnits(ms,s)) === 1ContextUnits(ms,s)\n        @test min(1ContextUnits(ms,s), 1FixedUnits(s)) === 1ContextUnits(ms,s)\n\n        # automatic conversion prohibited\n        @test_throws ErrorException min(1FixedUnits(s), 1FixedUnits(hr))\n        @test min(1FixedUnits(s), 1FixedUnits(s)) === 1FixedUnits(s)\n\n        # now move on, presuming that's working well.\n        @test max(1ft, 1m) == 1m\n        @test max(10J, 1kg*m^2/s^2) === 10J\n        @test max(1J//10, 1kg*m^2/s^2) === 1kg*m^2/s^2\n        @test @inferred(0m < 1.0m)\n        @test @inferred(2.0m < 3.0m)\n        @test @inferred(2.0m .< 3.0m)\n        @test !(@inferred 3.0m .< 3.0m)\n        @test @inferred(2.0m <= 3.0m)\n        @test @inferred(3.0m <= 3.0m)\n        @test @inferred(3.0m <= 3000.0mm)\n        @test @inferred(2.0m .<= 3.0m)\n        @test @inferred(3.0m .<= 3.0m)\n        @test !@inferred(1.0m/mm <= 999)\n        @test @inferred(1.0m/mm <= 1000)\n        @test !@inferred(1.1 <= 1000mm/m)\n        @test @inferred(1.0 <= 1000mm/m)\n        @test @inferred(1μm/m < 1)\n        @test @inferred(1 > 1μm/m)\n        @test @inferred(1μm/m < 1mm/m)\n        @test @inferred(1mm/m > 1μm/m)\n        @test_throws DimensionError 1m < 1kg\n        @test_throws DimensionError 1m < 1\n        @test_throws DimensionError 1 < 1m\n        @test_throws DimensionError 1mm/m < 1m\n        @test_throws DimensionError 1mm/m <= 1m\n        @test Base.rtoldefault(typeof(1.0u\"m\")) === Base.rtoldefault(typeof(1.0))\n        @test Base.rtoldefault(typeof(1u\"m\")) === Base.rtoldefault(Int)\n        @test_throws ErrorException Issue399(1)m < Issue399(2)m\n        @test_throws ErrorException Issue399(1)m == Issue399(1)m\n        @test @inferred(Issue399(1)m <= Issue399(2)m)\n\n        # check NaN handling in min, max (consistent with isless)\n        @test isequal(min(NaN * u\"m\", 1.0u\"m\"), 1.0u\"m\")\n        @test isequal(min(1.0u\"m\", NaN * u\"m\"), 1.0u\"m\")\n        @test isequal(max(NaN * u\"m\", 1.0u\"m\"), NaN * u\"m\")\n        @test isequal(max(1.0u\"m\", NaN * u\"m\"), NaN * u\"m\")\n    end\n    @testset \"> Addition and subtraction\" begin\n        @test @inferred(+(1A)) == 1A                    # Unary addition\n        @test @inferred(3m + 3m) == 6m                  # Binary addition\n        @test @inferred(-(1kg)) == (-1)*kg              # Unary subtraction\n        @test @inferred(3m - 2m) == 1m                  # Binary subtraction\n        @test @inferred(zero(1m)) === 0m                # Additive identity\n        @test @inferred(zero(typeof(1m))) === 0m\n        @test @inferred(zero(typeof(1.0m))) === 0.0m\n        @test_throws ArgumentError zero(Quantity{Int})\n        @test zero(Quantity{Int, 𝐋}) == 0m\n        @test zero(Quantity{Int, 𝐋}) isa Quantity{Int}\n        @test @inferred(π/2*u\"rad\" + 90u\"°\") ≈ π        # Dimless quantities\n        @test @inferred(π/2*u\"rad\" - 90u\"°\") ≈ 0        # Dimless quantities\n        @test @inferred(90u\"deg\" - 90u\"°\") == 0\n        @test_throws DimensionError 1+1m                # Dim mismatched\n        @test_throws DimensionError 1-1m\n    end\n    @testset \"> Multiplication\" begin\n        @test @inferred(FreeUnits(g)*FreeUnits(kg)) === FreeUnits(g*kg)\n        @test @inferred(ContextUnits(m,mm)*ContextUnits(kg,g)) ===\n            ContextUnits(m*kg,mm*g)\n        @test @inferred(ContextUnits(m,mm)*FreeUnits(g)) ===\n            ContextUnits(m*g,mm*kg)\n        @test @inferred(FreeUnits(g)*ContextUnits(m,mm)) ===\n            ContextUnits(m*g,mm*kg)\n        @test @inferred(FixedUnits(g)*FixedUnits(kg)) === FixedUnits(g*kg)\n        @test @inferred(FixedUnits(g)*FreeUnits(kg)) === FixedUnits(g*kg)\n        @test @inferred(FixedUnits(g)*ContextUnits(kg,kg)) === FixedUnits(g*kg)\n        @test @inferred(*(1s)) === 1s                     # Unary multiplication\n        @test @inferred(3m * 2cm) === 3cm * 2m            # Binary multiplication\n        @test @inferred((3m)*m) === 3*(m*m)               # Associative multiplication\n        @test @inferred(true*1kg) === 1kg                 # Boolean multiplication (T)\n        @test @inferred(false*1kg) === 0kg                # Boolean multiplication (F)\n        @test @inferred(true*(1+im)kg) === (1+im)kg       # Boolean-complex multiplication (T)\n        @test @inferred(false*(1+im)kg) === (0+0im)kg     # Boolean-complex multiplication (F)\n        @test @inferred((1+im)kg*true) === (1+im)kg       # Complex-boolean multiplication (T)\n        @test @inferred((1+im)kg*false) === (0+0im)kg     # Complex-boolean multiplication (F)\n        @test @inferred((NaN*kg)*false) === 0.0kg         # `false` acts as \"strong zero\"\n        @test @inferred(false*(-Inf*kg)) === -0.0kg       # `false` acts as \"strong zero\"\n        @test typeof(one(eltype([1.0s, 1kg]))) <: Float64 # issue 159, multiplicative identity\n        # Multiplication can be non-commutative\n        @test Quantity(MatNum([1 2; 3 4]), m) * MatNum([5 6; 7 8]) == Quantity(MatNum([19 22; 43 50]), m)\n        @test MatNum([5 6; 7 8]) * Quantity(MatNum([1 2; 3 4]), m) == Quantity(MatNum([23 34; 31 46]), m)\n    end\n    @testset \"> Division\" begin\n        @test 360° / 2 === 180.0°            # Issue 110\n        @test 360° // 2 === 180°//1\n        @test 2m // 5s == (2//5)*(m/s)       # Units propagate through rationals\n        @test (2//3)*m // 5 == (2//15)*m     # Quantity // Real\n        @test 5.0m // s === 5.0m/s           # Quantity // Unit. Just pass units through\n        @test s//(5m) === (1//5)*s/m         # Unit // Quantity. Will fail if denom is float\n        @test (m//2) === 1//2 * m            # Unit // Real\n        @test (2//m) === (2//1) / m          # Real // Unit\n        @test (m//s) === m/s                 # Unit // Unit\n        @test m / missing === missing        # Unit / missing\n        @test missing / m === missing        # Missing / Unit (// is not defined for Missing)\n        @test missing * u\"dB\" === missing   # Missing * MixedUnits\n        @test u\"dB\" * missing === missing   # MixedUnits * Missing\n        @test missing / u\"dB\" === missing   # Missing / MixedUnits\n        @test u\"dB\" / missing === missing   # MixedUnits / Missing\n        @test @inferred(div(10m, -3cm)) === -333\n        @test @inferred(div(10m, 3)) === 3m\n        @test @inferred(div(10, 3m)) === 3/m\n        @test @inferred(fld(10m, -3cm)) === -334\n        @test @inferred(fld(10m, 3)) === 3m\n        @test @inferred(fld(10, 3m)) === 3/m\n        @test @inferred(cld(10m, 3)) === 4m\n        @test @inferred(cld(10, 3m)) === 4/m\n        @test rem(10m, -3cm) == 1.0cm\n        @test mod(10m, -3cm) == -2.0cm\n        @test mod(1hr+3minute+5s, 24s) == 17s\n        @test mod2pi(360°) === 0°           # 2pi is 360°\n        @test mod2pi(0.5pi*u\"m/dm\") ≈ pi    # just testing the dimensionless fallback\n        @test modf(2.5rad) === (0.5, 2.0)\n        @test modf(-250cm/m) === (-1//2, -2//1)\n        @test_throws MethodError modf(1m)\n        @test @inferred(inv(s)) === s^-1\n        @test inv(ContextUnits(m,km)) === ContextUnits(m^-1,km^-1)\n        @test inv(FixedUnits(m)) === FixedUnits(m^-1)\n    end\n    @testset \"> Exponentiation\" begin\n        @test @inferred(m^3/m) === m^2\n        @test @inferred(𝐋^3/𝐋) === 𝐋^2\n        @test @inferred(sqrt(4m^2)) === 2.0m\n        @test sqrt(4m^(2//3)) === 2.0m^(1//3)\n        @test @inferred(sqrt(𝐋^2)) === 𝐋\n        @test @inferred(sqrt(m^2)) === m\n        @test @inferred(cbrt(8m^3)) === 2.0m\n        @test cbrt(8m) === 2.0m^(1//3)\n        @test @inferred(cbrt(𝐋^3)) === 𝐋\n        @test @inferred(cbrt(m^3)) === m\n        @test (2m)^3 === 8*m^3\n        @test (8m)^(1//3) === 2.0*m^(1//3)\n        @test @inferred(cis(90°)) == im\n        @test @inferred(cis((90 - rad2deg(1)*im)°)) ≈ ℯ*im\n\n        # Test inferrability of literal powers\n        _pow_m3(x) = x^-3\n        _pow_0(x) = x^0\n        _pow_3(x) = x^3\n        _pow_2_3(x) = x^(2//3)\n\n        @static if VERSION ≥ v\"1.8.0-DEV.501\"\n            @test @inferred(_pow_2_3(m)) == m^(2//3)\n            @test @inferred(_pow_2_3(𝐋)) == 𝐋^(2//3)\n            @test @inferred(_pow_2_3(1.0m)) == 1.0m^(2//3)\n        end\n\n        @test @inferred(_pow_m3(m)) == m^-3\n        @test @inferred(_pow_0(m)) == NoUnits\n        @test @inferred(_pow_3(m)) == m^3\n\n        @test @inferred(_pow_m3(𝐋)) == 𝐋^-3\n        @test @inferred(_pow_0(𝐋)) == NoDims\n        @test @inferred(_pow_3(𝐋)) == 𝐋^3\n\n        @test @inferred(_pow_m3(1.0m)) == 1.0m^-3\n        @test @inferred(_pow_0(1.0m)) == 1.0\n        @test @inferred(_pow_3(1.0m)) == 1.0m^3\n    end\n    @testset \"> Trigonometry\" begin\n        @test @inferred(sin(0.0rad)) == 0.0\n        @test @inferred(cos(π*rad)) == -1\n        @test @inferred(tan(π*rad/4)) ≈ 1\n        @test @inferred(csc(π*rad/2)) == 1\n        @test @inferred(sec(0.0*rad)) == 1\n        @test @inferred(cot(π*rad/4)) ≈ 1\n        @test @inferred(sin(90°)) == 1\n        @test @inferred(cos(0.0°)) == 1\n        @test @inferred(tan(45°)) == 1\n        @test @inferred(csc(90°)) == 1\n        @test @inferred(sec(0°)) == 1\n        @test @inferred(cot(45°)) == 1\n        @test @inferred(asin(1m/1000mm)) == 90°\n        @test @inferred(acos(-1mm/1000μm)) == π*rad\n        @test @inferred(atan(2000sqrt(3)ms/2.0s)) == 60°\n        @test @inferred(acsc(5.0Hz*0.2s)) == π/2\n        @test @inferred(asec(1m/1nm)) ≈ π/2\n        @test @inferred(acot(2sqrt(3)s/2000ms)) ≈ 30°\n\n        @test @inferred(sincos(250mrad)) === sincos(0.25)\n        @test @inferred(sincos((1+2im)rad)) === sincos(1+2im)\n        @test @inferred(sincos(30°)) === (sind(30), cosd(30))\n\n        @test @inferred(sinh(0.0rad)) == 0.0\n        @test @inferred(sinh(1J/N/m) + cosh(1rad)) ≈ MathConstants.e\n        @test @inferred(tanh(1m/1μm)) == 1\n        @test @inferred(csch(0.0°)) == Inf\n        @test @inferred(sech(0K/Ra)) == 1\n        @test @inferred(coth(1e3m*mm^-1)) == 1\n        @test @inferred(asinh(0.0mg/kg)) == 0\n        @test @inferred(acosh(1mm/1000μm)) == 0\n        @test @inferred(atanh(0W*s/J)) == 0\n        @test @inferred(acsch(hr/yr * 0)) == Inf\n        @test @inferred(asech(1.0m/1000.0mm)) == 0\n        @test @inferred(acoth(1km/1000m)) == Inf\n\n        @test @inferred(sinpi(rad/2)) == 1\n        @test @inferred(cospi(1rad)) == -1\n        @test @inferred(sinc(1rad)) === 0\n        @test @inferred(cosc(1ft/3inch)) === 0.25\n        @test @inferred(cispi(rad/2)) === complex(0.0, 1.0)\n        @test @inferred(cispi(rad/2 + im*rad)) ≈ complex(0.0, exp(-π))\n        @test @inferred(sincospi(rad/2)) === (1.0, 0.0)\n        if isdefined(Base, :tanpi)\n            @test @inferred(tanpi(1f0rad)) === tanpi(1f0)\n            @test @inferred(tanpi(250mrad)) === tanpi(0.25)\n            @test @inferred(tanpi(-100mm/m)) === tanpi(-1//10)\n        end\n\n        @test @inferred(atan(m*sqrt(3),1m)) ≈ 60°\n        @test @inferred(atan(m*sqrt(3),1.0m)) ≈ 60°\n        @test @inferred(atan(m*sqrt(3),1000mm)) ≈ 60°\n        @test @inferred(atan(m*sqrt(3),1e+3mm)) ≈ 60°\n        @test_throws DimensionError atan(m*sqrt(3),1e+3s)\n        @test @inferred(angle((3im)*V)) ≈ 90°\n\n        @test @inferred(sincosd(5°)) == sincos(5°) == (sind(5°), cosd(5°))\n    end\n    @testset \"> Exponentials and logarithms\" begin\n        for f in (exp, exp10, exp2, expm1, log, log10, log1p, log2)\n            @test f(1.0 * u\"m/dm\") ≈ f(10)\n        end\n    end\n    @testset \"> Matrix inversion\" begin\n        @test inv([1 1; -1 1]u\"nm\") ≈ [0.5 -0.5; 0.5 0.5]u\"nm^-1\"\n    end\n    @testset \"> Is functions\" begin\n        @test_throws ErrorException isinteger(1.0m)\n        @test isinteger(1.4m/mm)\n        @test !isinteger(1.4mm/m)\n        @test_throws ErrorException iseven(1.0m)\n        @test iseven(2rad)\n        @test !iseven(1rad)\n        if hasmethod(iseven, (Float64,))\n            @test iseven(0.5m/mm)\n            @test !iseven(0.125m/mm)\n        end\n        @test_throws ErrorException isodd(1.0m)\n        @test isodd(1rad)\n        @test !isodd(2rad)\n        if hasmethod(isodd, (Float64,))\n            @test isodd(0.125m/mm)\n            @test !isodd(0.5m/mm)\n        end\n        @test isfinite(1.0m)\n        @test !isfinite(Inf*m)\n        @test isnan(NaN*m)\n        @test !isnan(1.0m)\n        @static if VERSION ≥ v\"1.7.0-DEV.119\"\n            @test isunordered(NaN*m)\n            @test !isunordered(Inf*m)\n            @test !isunordered(1.0*m)\n        end\n    end\n    @testset \"> Floating point tests\" begin\n        @test isapprox(1.0u\"m\",(1.0+eps(1.0))u\"m\")\n        @test isapprox(1.0u\"μm/m\",1e-6)\n        @test !isapprox(1.0u\"μm/m\",1e-7)\n        @test !isapprox(1.0u\"m\",5)\n        @test frexp(1.5m) == (0.75m, 1.0)\n        @test unit(nextfloat(0.0m)) == m\n        @test unit(nextfloat(0.0m, 4)) == m\n        @test ustrip(nextfloat(0.0m, 4)) == nextfloat(0.0, 4)\n        @test unit(prevfloat(0.0m)) == m\n        @test unit(prevfloat(0.0m, 4)) == m\n        @test ustrip(prevfloat(0.0m, 4)) == prevfloat(0.0, 4)\n\n        # NaN behavior\n        @test NaN*m != NaN*m\n        @test isequal(NaN*m, NaN*m)\n\n        @test isapprox(1.0u\"m\", 1.1u\"m\"; atol=0.2u\"m\")\n        @test !isapprox(1.0u\"m\", 1.1u\"m\"; atol=0.05u\"m\")\n        @test isapprox(1.0u\"m\", 1.1u\"m\"; atol=200u\"mm\")\n        @test !isapprox(1.0u\"m\", 1.1u\"m\"; atol=50u\"mm\")\n        @test isapprox(1.0u\"m\", 1.1u\"m\"; rtol=0.2)\n        @test !isapprox(1.0u\"m\", 1.1u\"m\"; rtol=0.05)\n\n        # isapprox with dimensionless Quantity vs Number and atol\n        @test isapprox(1u\"rad\", 1.1; atol=0.5u\"rad\")\n        @test !isapprox(1u\"rad\", 1.1; atol=0.01u\"rad\")\n        @test isapprox(1.1, 1u\"rad\"; atol=0.5u\"rad\")\n        @test isapprox(1.0u\"rad\", 1.1; atol=0.5)\n        @test isapprox(1.0u\"rad\", 1.01; rtol=0.1)\n\n        # Issue 465:\n        z = fill((1+im)m, 2, 3)\n        @test !isapprox(z, 2z)\n        @test isapprox(z, z * (1 + 1e-15))\n\n        # Test eps\n        @test eps(1.0u\"s\") == eps(1.0)u\"s\"\n        @test eps(typeof(1.0u\"s\")) == eps(Float64)\n\n        # Test promotion behavior\n        @test !isapprox(1.0u\"m\", 1.0u\"s\")\n        @test isapprox(1.0u\"m\", 1000.0u\"mm\")\n        @test_throws ErrorException isapprox(1.0*FixedUnits(u\"m\"), 1000.0*FixedUnits(u\"mm\"))\n    end\nend\n\n@testset \"Fast mathematics\" begin\n    @testset \"> fma and muladd\" begin\n        m2cm = ContextUnits(m,cm)\n        m2mm = ContextUnits(m,mm)\n        mm2cm = ContextUnits(mm,cm)\n        cm2cm = ContextUnits(cm,cm)\n        fm, fmm = FixedUnits(m), FixedUnits(mm)\n        @test @inferred(fma(2.0, 3.0m, 1.0m)) === 7.0m               # llvm good\n        @test @inferred(fma(2.0, 3.0m2cm, 1.0mm2cm)) === 600.1cm2cm\n        @test @inferred(fma(2.0, 3.0fm, 1.0fm)) === 7.0fm\n        @test @inferred(fma(2.0, 3.0m, 35mm)) === 6.035m             # llvm good\n        @test @inferred(fma(2.0, 3.0m2cm, 35mm2cm)) === 603.5cm2cm\n        @test_throws ErrorException fma(2.0, 3.0fm, 35fmm)  #automatic conversion prohibited\n        @test @inferred(fma(2.0m, 3.0, 35mm)) === 6.035m             # llvm good\n        @test @inferred(fma(2.0m2cm, 3.0, 35mm2cm)) === 603.5cm2cm\n        @test @inferred(fma(2.0m, 1.0/m, 3.0)) === 5.0               # llvm good\n        @test @inferred(fma(2.0m2cm, 1.0/m2mm, 3.0)) === 5.0\n        @test @inferred(fma(2.0cm, 1.0/s, 3.0mm/s)) === .023m/s      # llvm good\n        @test @inferred(fma(2.0cm2cm, 1.0/s, 3.0mm/s)) === 2.3cm2cm/s\n        @test @inferred(fma(2m, 1/s, 3m/s)) === 5m/s                 # llvm good\n        @test @inferred(fma(2, 1.0μm/m, 1)) === 1.000002             # llvm good\n        @test @inferred(fma(1.0mm/m, 1.0mm/m, 1.0mm/m)) === 0.001001 # llvm good\n        @test @inferred(fma(1.0mm/m, 1.0, 1.0)) ≈ 1.001              # llvm good\n        @test @inferred(fma(1.0, 1.0μm/m, 1.0μm/m)) === 2.0μm/m      # llvm good\n        @test @inferred(fma(2, 1.0, 1μm/m)) === 2.000001             # llvm BAD\n        @test @inferred(fma(2, 1μm/m, 1mm/m)) === 501//500000    # llvm BAD\n        @test @inferred(muladd(2.0, 3.0m, 1.0m)) === 7.0m\n        @test @inferred(muladd(2.0, 3.0m, 35mm)) === 6.035m\n        @test @inferred(muladd(2.0m, 3.0, 35mm)) === 6.035m\n        @test @inferred(muladd(2.0m, 1.0/m, 3.0)) === 5.0\n        @test @inferred(muladd(2.0cm, 1.0/s, 3.0mm/s)) === .023m/s\n        @test @inferred(muladd(2m, 1/s, 3m/s)) === 5m/s\n        @test @inferred(muladd(2, 1.0μm/m, 1)) === 1.000002\n        @test @inferred(muladd(1.0mm/m, 1.0mm/m, 1.0mm/m)) === 0.001001\n        @test @inferred(muladd(1.0mm/m, 1.0, 1.0)) ≈ 1.001\n        @test @inferred(muladd(1.0, 1.0μm/m, 1.0μm/m)) === 2.0μm/m\n        @test @inferred(muladd(2, 1.0, 1μm/m)) === 2.000001\n        @test @inferred(muladd(2, 1μm/m, 1mm/m)) === 501//500000\n        @test_throws DimensionError fma(2m, 1/m, 1m)\n        @test_throws DimensionError fma(2, 1m, 1V)\n        @test muladd(1s, 1.0mol/s, 2.0mol) === 3.0mol               # issue 138\n    end\n    @testset \"> @fastmath\" begin\n        one32 = one(Float32)*m\n        eps32 = eps(Float32)*m\n        eps32_2 = eps32/2\n\n        # Note: Cannot use local functions since these are not yet optimized\n        fm_ieee_32(x) = x + eps32_2 + eps32_2\n        fm_fast_32(x) = @fastmath x + eps32_2 + eps32_2\n        @test fm_ieee_32(one32) == one32\n        @test (fm_fast_32(one32) == one32 ||\n            fm_fast_32(one32) == one32 + eps32 > one32)\n\n        one64 = one(Float64)*m\n        eps64 = eps(Float64)*m\n        eps64_2 = eps64/2\n\n        # Note: Cannot use local functions since these are not yet optimized\n        fm_ieee_64(x) = x + eps64_2 + eps64_2\n        fm_fast_64(x) = @fastmath x + eps64_2 + eps64_2\n        @test fm_ieee_64(one64) == one64\n        @test (fm_fast_64(one64) == one64 ||\n            fm_fast_64(one64) == one64 + eps64 > one64)\n\n        # check updating operators\n        fm_ieee_64_upd(x) = (r=x; r+=eps64_2; r+=eps64_2)\n        fm_fast_64_upd(x) = @fastmath (r=x; r+=eps64_2; r+=eps64_2)\n        @test fm_ieee_64_upd(one64) == one64\n        @test (fm_fast_64_upd(one64) == one64 ||\n            fm_fast_64_upd(one64) == one64 + eps64 > one64)\n\n        for T in (Float32, Float64, BigFloat)\n            _zero = convert(T, 0)*m\n            _one = convert(T, 1)*m + eps(T)*m\n            _two = convert(T, 2)*m + 1m//10\n            _three = convert(T, 3)*m + 1m//100\n\n            @test isapprox((@fastmath +_two), +_two)\n            @test isapprox((@fastmath -_two), -_two)\n            @test isapprox((@fastmath _zero+_one+_two), _zero+_one+_two)\n            @test isapprox((@fastmath _zero-_one-_two), _zero-_one-_two)\n            @test isapprox((@fastmath _one*_two*_three), _one*_two*_three)\n            @test isapprox((@fastmath _one/_two/_three), _one/_two/_three)\n            @test isapprox((@fastmath rem(_two, _three)), rem(_two, _three))\n            @test isapprox((@fastmath mod(_two, _three)), mod(_two, _three))\n            @test (@fastmath cmp(_two, _two)) == cmp(_two, _two)\n            @test (@fastmath cmp(_two, _three)) == cmp(_two, _three)\n            @test (@fastmath cmp(_three, _two)) == cmp(_three, _two)\n            @test (@fastmath _one/_zero) == convert(T, Inf)\n            @test (@fastmath -_one/_zero) == -convert(T, Inf)\n            @test isnan(@fastmath _zero/_zero) # must not throw\n\n            for x in (_zero, _two, convert(T, Inf)*m, convert(T, NaN)*m)\n                @test (@fastmath isfinite(x))\n                @test !(@fastmath isinf(x))\n                @test !(@fastmath isnan(x))\n                @test !(@fastmath issubnormal(x))\n            end\n        end\n\n        for T in (Complex{Float32}, Complex{Float64}, Complex{BigFloat})\n            _zero = convert(T, 0)*m\n            _one = convert(T, 1)*m + im*eps(real(convert(T,1)))*m\n            _two = convert(T, 2)*m + im*m//10\n            _three = convert(T, 3)*m + im*m//100\n\n            @test isapprox((@fastmath +_two), +_two)\n            @test isapprox((@fastmath -_two), -_two)\n            @test isapprox((@fastmath _zero+_one+_two), _zero+_one+_two)\n            @test isapprox((@fastmath _zero-_one-_two), _zero-_one-_two)\n            @test isapprox((@fastmath _one*_two*_three), _one*_two*_three)\n            @test isapprox((@fastmath _one/_two/_three), _one/_two/_three)\n            @test (@fastmath _three == _two) == (_three == _two)\n            @test (@fastmath _three != _two) == (_three != _two)\n            @test isnan(@fastmath _one/_zero)  # must not throw\n            @test isnan(@fastmath -_one/_zero) # must not throw\n            @test isnan(@fastmath _zero/_zero) # must not throw\n\n            for x in (_zero, _two, convert(T, Inf)*m, convert(T, NaN)*m)\n                @test (@fastmath isfinite(x))\n                @test !(@fastmath isinf(x))\n                @test !(@fastmath isnan(x))\n                @test !(@fastmath issubnormal(x))\n            end\n        end\n\n\n        # real arithmetic\n        for T in (Float32, Float64, BigFloat)\n            half = 1m/convert(T, 2)\n            third = 1m/convert(T, 3)\n\n            for f in (:+, :-, :abs, :abs2, :conj, :inv, :sign, :sqrt)\n                @test isapprox((@eval @fastmath $f($half)), (@eval $f($half)))\n                @test isapprox((@eval @fastmath $f($third)), (@eval $f($third)))\n            end\n            for f in (:+, :-, :*, :/, :%, :(==), :!=, :<, :<=, :>, :>=,\n                      :atan, :hypot, :max, :min)\n                @test isapprox((@eval @fastmath $f($half, $third)),\n                               (@eval $f($half, $third)))\n                @test isapprox((@eval @fastmath $f($third, $half)),\n                               (@eval $f($third, $half)))\n            end\n            for f in (:minmax,)\n                @test isapprox((@eval @fastmath $f($half, $third))[1],\n                               (@eval $f($half, $third))[1])\n                @test isapprox((@eval @fastmath $f($half, $third))[2],\n                               (@eval $f($half, $third))[2])\n                @test isapprox((@eval @fastmath $f($third, $half))[1],\n                               (@eval $f($third, $half))[1])\n                @test isapprox((@eval @fastmath $f($third, $half))[2],\n                               (@eval $f($third, $half))[2])\n            end\n\n            half = 1°/convert(T, 2)\n            third = 1°/convert(T, 3)\n            for f in (:cos, :sin, :tan, :cis)\n                @test isapprox((@eval @fastmath $f($half)), (@eval $f($half)))\n                @test isapprox((@eval @fastmath $f($third)), (@eval $f($third)))\n            end\n            @test all(x -> isapprox(x...), Iterators.zip((@eval @fastmath sincos($half)), (@eval sincos($half))))\n            @test all(x -> isapprox(x...), Iterators.zip((@eval @fastmath sincos($third)), (@eval sincos($third))))\n        end\n\n        # complex arithmetic\n        for T in (Complex{Float32}, Complex{Float64}, Complex{BigFloat})\n            half = (1+1im)V/T(2)\n            third = (1-1im)V/T(3)\n\n            # some of these functions promote their result to double\n            # precision, but we want to check equality at precision T\n            rtol = Base.rtoldefault(real(T))\n\n            for f in (:+, :-, :abs, :abs2, :conj, :inv, :sign, :sqrt)\n                @test isapprox((@eval @fastmath $f($half)), (@eval $f($half)), rtol=rtol)\n                @test isapprox((@eval @fastmath $f($third)), (@eval $f($third)), rtol=rtol)\n            end\n            for f in (:+, :-, :*, :/, :(==), :!=)\n                @test isapprox((@eval @fastmath $f($half, $third)),\n                               (@eval $f($half, $third)), rtol=rtol)\n                @test isapprox((@eval @fastmath $f($third, $half)),\n                               (@eval $f($third, $half)), rtol=rtol)\n            end\n\n            _d = 90°/T(2)\n            @test isapprox((@fastmath cis(_d)), cis(_d))\n        end\n\n        # mixed real/complex arithmetic\n        for T in (Float32, Float64, BigFloat)\n            CT = Complex{T}\n            half = 1V/T(2)\n            third = 1V/T(3)\n            chalf = (1+1im)V/CT(2)\n            cthird = (1-1im)V/CT(3)\n\n            for f in (:+, :-, :*, :/, :(==), :!=)\n                @test isapprox((@eval @fastmath $f($chalf, $third)),\n                               (@eval $f($chalf, $third)))\n                @test isapprox((@eval @fastmath $f($half, $cthird)),\n                               (@eval $f($half, $cthird)))\n                @test isapprox((@eval @fastmath $f($cthird, $half)),\n                               (@eval $f($cthird, $half)))\n                @test isapprox((@eval @fastmath $f($third, $chalf)),\n                               (@eval $f($third, $chalf)))\n            end\n\n            @test isapprox((@fastmath third^3), third^3)\n            @test isapprox((@fastmath chalf/third), chalf/third)\n            @test isapprox((@fastmath chalf^3), chalf^3)\n        end\n    end\nend\n\n@testset \"Rounding\" begin\n    @test_throws ErrorException floor(3.7m)\n    @test_throws ErrorException ceil(3.7m)\n    @test_throws ErrorException trunc(3.7m)\n    @test_throws ErrorException round(3.7m)\n    @test_throws ErrorException floor(Integer, 3.7m)\n    @test_throws ErrorException ceil(Integer, 3.7m)\n    @test_throws ErrorException trunc(Integer, 3.7m)\n    @test_throws ErrorException round(Integer, 3.7m)\n    @test_throws ErrorException floor(Int, 3.7m)\n    @test_throws ErrorException ceil(Int, 3.7m)\n    @test_throws ErrorException trunc(Int, 3.7m)\n    @test_throws ErrorException round(Int, 3.7m)\n    @test floor(1.0314m/mm) === 1031.0\n    @test floor(1.0314m/mm; digits=1) === 1031.4\n    @test ceil(1.0314m/mm) === 1032.0\n    @test ceil(1.0314m/mm; digits=1) === 1031.4\n    @test trunc(-1.0314m/mm) === -1031.0\n    @test trunc(-1.0314m/mm; digits=1) === -1031.4\n    @test round(1.0314m/mm) === 1031.0\n    @test round(1.0314m/mm; digits=1) === 1031.4\n    @test floor(Integer, 1.0314m/mm) === Integer(1031.0)\n    @test ceil(Integer, 1.0314m/mm) === Integer(1032.0)\n    @test trunc(Integer, -1.0314m/mm) === Integer(-1031.0)\n    @test round(Integer, 1.0314m/mm) === Integer(1031.0)\n    @test floor(Int16, 1.0314m/mm) === Int16(1031.0)\n    @test ceil(Int16, 1.0314m/mm) === Int16(1032.0)\n    @test trunc(Int16, -1.0314m/mm) === Int16(-1031.0)\n    @test round(Int16, 1.0314m/mm) === Int16(1031.0)\n    @test floor(typeof(1mm), 1.0314m) === 1031mm\n    @test floor(typeof(1.0mm), 1.0314m) === 1031.0mm\n    @test floor(typeof(1.0mm), 1.0314m; digits=1) === 1031.4mm\n    @test ceil(typeof(1mm), 1.0314m) === 1032mm\n    @test ceil(typeof(1.0mm), 1.0314m) === 1032.0mm\n    @test ceil(typeof(1.0mm), 1.0314m; digits=1) === 1031.4mm\n    @test trunc(typeof(1mm), -1.0314m) === -1031mm\n    @test trunc(typeof(1.0mm), -1.0314m) === -1031.0mm\n    @test trunc(typeof(1.0mm), -1.0314m; digits=1) === -1031.4mm\n    @test round(typeof(1mm), 1.0314m) === 1031mm\n    @test round(typeof(1.0mm), 1.0314m) === 1031.0mm\n    @test round(typeof(1.0mm), 1.0314m; digits=1) === 1031.4mm\n    @test round(typeof(1.0°), 1.125°) === 1.0°\n    @test round(typeof(1.0°), 1.125°, RoundUp) === 2.0°\n    @test round(typeof(1.0°), 1.125°, digits=1) === 1.1°\n    @test round(typeof(1.0°), 1.125°, RoundUp, digits=1) === 1.2°\n    @test round(typeof(1.0°), 1rad) === 57.0°\n    @test round(typeof(1.0°), 1rad, RoundUp) === 58.0°\n    @test floor(typeof(1.0°), 1.125°) === 1.0°\n    @test floor(typeof(1.0°), 1.125°, digits=1) === 1.1°\n    @test round(u\"inch\", 1.0314m) === 41.0u\"inch\"\n    @test round(Int, u\"inch\", 1.0314m) === 41u\"inch\"\n    @test round(typeof(1m), 137cm) === 1m\n    @test round(137cm/m) === 1//1\n    @test round(u\"m\", -125u\"cm\", sigdigits=2) === -1.2u\"m\"\n    @test round(u\"m\", (125//1)u\"cm\", sigdigits=2) === 1.2u\"m\"\n    @test round(u\"m\", -125u\"cm\", RoundNearestTiesUp, sigdigits=2) === -1.2u\"m\"\n    @test round(u\"m\", (125//1)u\"cm\", RoundNearestTiesUp, sigdigits=2) === 1.3u\"m\"\n    @test floor(u\"m\", -125u\"cm\", sigdigits=2) === -1.3u\"m\"\n    @test floor(u\"m\", (125//1)u\"cm\", sigdigits=2) === 1.2u\"m\"\n    @test ceil(u\"m\", -125u\"cm\", sigdigits=2) === -1.2u\"m\"\n    @test ceil(u\"m\", (125//1)u\"cm\", sigdigits=2) === 1.3u\"m\"\n    @test trunc(u\"m\", -125u\"cm\", sigdigits=2) === -1.2u\"m\"\n    @test trunc(u\"m\", (125//1)u\"cm\", sigdigits=2) === 1.2u\"m\"\nend\n\n@testset \"Sgn, abs, &c.\" begin\n    @test @inferred(abs(3V+4V*im)) == 5V\n    @test @inferred(norm(3V+4V*im)) == 5V\n    @test @inferred(abs2(3V+4V*im)) == 25V^2\n    @test @inferred(abs(-3m)) == 3m\n    @test @inferred(abs2(-3m)) == 9m^2\n    @test @inferred(sign(-3.3m)) == -1.0\n    @test @inferred(signbit(0.0m)) == false\n    @test @inferred(signbit(-0.0m)) == true\n    @test @inferred(copysign(3.0m, -4.0s)) == -3.0m\n    @test @inferred(copysign(3.0m, 4)) == 3.0m\n    @test @inferred(copysign(3, -4.0m)) == -3\n    @test @inferred(flipsign(3.0m, -4)) == -3.0m\n    @test @inferred(flipsign(-3.0m, -4)) == 3.0m\n    @test @inferred(flipsign(-3.0, -4m)) == 3.0\n    @test @inferred(flipsign(-3, 4.0m)) == -3\n    @test @inferred(flipsign(3.0m, -4s)) == -3.0m\n    @test @inferred(flipsign(-3m, 4.0s)) == -3m\n    @test @inferred(flipsign((3.0+4.0im)m, -4)) == (-3.0-4.0im)m\n    @test @inferred(flipsign((-3.0+4.0im)m, -4)) == (3.0-4.0im)m\n    @test @inferred(flipsign(-3+4im, -4m)) == 3-4im\n    @test @inferred(flipsign(-3.0+4.0im, 4m)) == -3.0+4.0im\n    @test @inferred(flipsign((3.0+4.0im)m, -4s)) == (-3.0-4.0im)m\n    @test @inferred(flipsign((-3+4im)m, 4.0s)) == (-3+4im)m\n    @test @inferred(real(3m)) == 3.0m\n    @test @inferred(real((3+4im)V)) == 3V\n    @test @inferred(imag(3m)) == 0m\n    @test @inferred(imag((3+4im)V)) == 4V\n    @test @inferred(conj(3m)) == 3m\n    @test @inferred(conj((3+4im)V)) == (3-4im)V\n    @test @inferred(Base.hastypemax(typeof(1.0m))) === Base.hastypemax(typeof(1.0))\n    @test @inferred(Base.hastypemax(typeof(big(1)m))) === Base.hastypemax(typeof(big(1)))\n    @test @inferred(typemin(1.0m)) == -Inf*m\n    @test @inferred(typemax(typeof(1.0m))) == Inf*m\n    @test @inferred(typemin(0x01*m)) == 0x00*m\n    @test @inferred(typemax(typeof(0x01*m))) == 0xff*m\n    @test @inferred(rand(typeof(1u\"m\"))) isa typeof(1u\"m\")\n    @test @inferred(rand(MersenneTwister(0), typeof(1u\"m\"))) isa typeof(1u\"m\")\nend\n\n@testset \"Collections\" begin\n    @testset \"> Ranges\" begin\n        @testset \">> Some of test/ranges.jl, with units\" begin\n            @test @inferred(size(10m:1m:0m)) == (0,)\n            @test length(1m:.2m:2m) == 6\n            @test length(1.0m:.2m:2.0m) == 6\n            @test length(2m:-.2m:1m) == 6\n            @test length(2.0m:-.2m:1.0m) == 6\n            @test @inferred(length(2m:.2m:1m)) == 0\n            @test length(2.0m:.2m:1.0m) == 0\n\n            @test length(1m:2m:0m) == 0\n            L32 = range(Int32(1)*m, stop=Int32(4)*m, length=4)\n            L64 = range(Int64(1)*m, stop=Int64(4)*m, length=4)\n            @test L32[1] == 1m && L64[1] == 1m\n            @test L32[2] == 2m && L64[2] == 2m\n            @test L32[3] == 3m && L64[3] == 3m\n            @test L32[4] == 4m && L64[4] == 4m\n\n            r = 5m:-1m:1m\n            @test @inferred(r[1])==5m\n            @test r[2]==4m\n            @test r[3]==3m\n            @test r[4]==2m\n            @test r[5]==1m\n\n            @test length(.1m:.1m:.3m) == 3\n            # @test length(1.1m:1.1m:3.3m) == 3\n            @test @inferred(length(1.1m:1.3m:3m)) == 2\n            @test length(1m:1m:1.8m) == 1\n\n            @test (1m:2m:13m)[2:6] == 3m:2m:11m\n            @test typeof((1m:2m:13m)[2:6]) == typeof(3m:2m:11m)\n            @test (1m:2m:13m)[2:3:7] == 3m:6m:13m\n            @test typeof((1m:2m:13m)[2:3:7]) == typeof(3m:6m:13m)\n        end\n        @testset \">> StepRange\" begin\n            r = @inferred(colon(1m, 1m, 5m))\n            @test isa(r, StepRange{typeof(1m)})\n            @test @inferred(length(r)) === 5\n            @test @inferred(step(r)) === 1m\n            @test @inferred(first(range(1mm, step=2m, length=4))) === 1mm\n            @test @inferred(step(range(1mm, step=2m, length=4))) === 2000mm\n            @test @inferred(last(range(1mm, step=2m, length=4))) === 6001mm\n            @test @inferred(first(range(1m, step=2mm, length=4))) === (1//1)m\n            @test @inferred(step(range(1m, step=2mm, length=4))) === (1//500)m\n            @test @inferred(last(range(1m, step=2mm, length=4))) === (503//500)m\n            @test_throws DimensionError(1m, 2V) range(1m, step=2V, length=5)\n            @test_throws ArgumentError 1m:0m:5m\n        end\n        @testset \">> StepRangeLen\" begin\n            @test isa(@inferred(colon(1.0m, 1m, 5m)), StepRangeLen{typeof(1.0m)})\n            @test @inferred(length(1.0m:1m:5m)) === 5\n            @test @inferred(step(1.0m:1m:5m)) === 1.0m\n            @test @inferred(length(0:10°:360°)) == 37 # issue 111\n            @test @inferred(length(0.0:10°:2pi)) == 37 # issue 111 fallout\n            @test @inferred(last(0°:0.1:360°)) === 6.2 # issue 111 fallout\n            @test @inferred(first(range(1mm, step=0.1mm, length=50))) === 1.0mm # issue 111\n            @test @inferred(step(range(1mm, step=0.1mm, length=50))) === 0.1mm # issue 111\n            @test @inferred(last(range(0, step=10°, length=37))) == 2pi\n            @test @inferred(last(range(0°, step=2pi/36, length=37))) == 2pi\n            @test step(range(1.0m, step=1m, length=5)) === 1.0m\n            @test @inferred(first(range(1.0mm, step=2.0m, length=4))) === 1.0mm\n            @test @inferred(step(range(1.0mm, step=2.0m, length=4))) === 2000.0mm\n            @test @inferred(last(range(1.0mm, step=2.0m, length=4))) === 6001.0mm\n            @test @inferred(first(range(1.0m, step=2.0mm, length=4))) === 1.0m\n            @test @inferred(step(range(1.0m, step=2.0mm, length=4))) === 0.002m\n            @test @inferred(last(range(1.0m, step=2.0mm, length=4))) === 1.006m\n            @test_throws DimensionError range(1.0m, step=1.0V, length=5)\n            @test_throws ArgumentError 1.0m:0.0m:5.0m\n            @test (-2.0Hz:1.0Hz:2.0Hz)/1.0Hz == -2.0:1.0:2.0  # issue 160\n            @test (range(0, stop=2, length=5) * u\"°\")[2:end] ==\n                range(0.5, stop=2, length=4) * u\"°\"  # issue 241\n            @test range(big(1.0)m, step=big(1.0)m, length=5) == (big(1.0):big(1.0):big(5.0))*m\n        end\n        @testset \">> LinSpace\" begin\n            # Not using Compat.range for these because kw args don't infer in julia 0.6.2\n            @test isa(@inferred(range(1.0m, stop=3.0m, length=5)),\n                StepRangeLen{typeof(1.0m), Base.TwicePrecision{typeof(1.0m)}})\n            @test isa(@inferred(range(1.0m, stop=10m, length=5)),\n                StepRangeLen{typeof(1.0m), Base.TwicePrecision{typeof(1.0m)}})\n            @test isa(@inferred(range(1m, stop=10.0m, length=5)),\n                StepRangeLen{typeof(1.0m), Base.TwicePrecision{typeof(1.0m)}})\n            @test isa(@inferred(range(1m, stop=10m, length=5)),\n                StepRangeLen{typeof(1.0m), Base.TwicePrecision{typeof(1.0m)}})\n            @test_throws Unitful.DimensionError range(1m, stop=10, length=5)\n            @test_throws Unitful.DimensionError range(1, stop=10m, length=5)\n            r = range(1m, stop=3m, length=3)\n            @test r[1:2:end] == range(1m, stop=3m, length=2)\n        end\n        @testset \">> Range → Array\" begin\n            @test isa(collect(1m:1m:5m), Array{typeof(1m),1})\n            @test isa(collect(1m:2m:10m), Array{typeof(1m),1})\n            @test isa(collect(1.0m:2m:10m), Array{typeof(1.0m),1})\n            @test isa(collect(range(1.0m, stop=10.0m, length=5)),\n                Array{typeof(1.0m),1})\n        end\n        @testset \">> unit multiplication\" begin\n            @test @inferred((1:5)*mm) === 1mm:1mm:5mm\n            @test @inferred(mm*(1:5)) === 1mm:1mm:5mm\n            @test @inferred((1:2:5)*mm) === 1mm:2mm:5mm\n            @test @inferred((1.0:2.0:5.01)*mm) === 1.0mm:2.0mm:5.0mm\n            r = @inferred(range(0.1, step=0.1, length=3) * 1.0s)\n            @test r[3] === 0.3s\n            @test *(1:5, mm, s^-1) === 1mm*s^-1:1mm*s^-1:5mm*s^-1\n            @test *(1:5, mm, s^-1, mol^-1) === 1mm*s^-1*mol^-1:1mm*s^-1*mol^-1:5mm*s^-1*mol^-1\n            @test @inferred((0:2) * 3f0m) === StepRangeLen{typeof(0f0m)}(0.0m, 3.0m, 3) # issue #477\n            @test @inferred(3f0m * (0:2)) === StepRangeLen{typeof(0f0m)}(0.0m, 3.0m, 3) # issue #477\n            @test @inferred((0f0:2f0) * 3f0m) === 0f0m:3f0m:6f0m\n            @test @inferred(3f0m * (0.0:2.0)) === 0.0m:3.0m:6.0m\n            @test @inferred(LinRange(0f0, 1f0, 3) * 3f0m) === LinRange(0f0m, 3f0m, 3)\n            @test @inferred(3f0m * LinRange(0.0, 1.0, 3)) === LinRange(0.0m, 3.0m, 3)\n            @test @inferred(1.0s * range(0.1, step=0.1, length=3)) === @inferred(range(0.1, step=0.1, length=3) * 1.0s)\n        end\n        @testset \">> broadcasting\" begin\n            @test @inferred((1:5) .* mm) === 1mm:1mm:5mm\n            @test @inferred(mm .* (1:5)) === 1mm:1mm:5mm\n            @test @inferred((1:2:5) .* mm) === 1mm:2mm:5mm\n            @test @inferred((1.0:2.0:5.01) .* mm) === 1.0mm:2.0mm:5.0mm\n            r = @inferred(range(0.1, step=0.1, length=3) .* 1.0s)\n            @test r[3] === 0.3s\n            @test @inferred((0:2) .* 3f0m) === StepRangeLen{typeof(0f0m)}(0.0m, 3.0m, 3) # issue #477\n            @test @inferred(3f0m .* (0:2)) === StepRangeLen{typeof(0f0m)}(0.0m, 3.0m, 3) # issue #477\n            @test @inferred((0f0:2f0) .* 3f0m) === 0f0m:3f0m:6f0m\n            @test @inferred(3f0m .* (0.0:2.0)) === 0.0m:3.0m:6.0m\n            @test @inferred(LinRange(0f0, 1f0, 3) .* 3f0m) === LinRange(0f0m, 3f0m, 3)\n            @test @inferred(3f0m .* LinRange(0.0, 1.0, 3)) === LinRange(0.0m, 3.0m, 3)\n            @test @inferred(1.0s .* range(0.1, step=0.1, length=3)) === @inferred(range(0.1, step=0.1, length=3) * 1.0s)\n\n            @test @inferred((1:2:5) .* cm .|> mm) === 10mm:20mm:50mm\n            @test mm.((1:2:5) .* cm) === 10mm:20mm:50mm\n            @test @inferred(StepRange(1cm,1mm,2cm) .|> km) === (1//100_000)km:(1//1_000_000)km:(2//100_000)km\n\n            @test @inferred((1:2:5) .* km .|> upreferred) === 1000m:2000m:5000m\n            @test @inferred((1:2:5)km .|> upreferred) === 1000m:2000m:5000m\n            @test @inferred((1:2:5) .|> upreferred) === 1:2:5\n            @test @inferred((1.0:2.0:5.0) .* km .|> upreferred) === 1000.0m:2000.0m:5000.0m\n            @test @inferred((1.0:2.0:5.0)km .|> upreferred) === 1000.0m:2000.0m:5000.0m\n            @test @inferred((1.0:2.0:5.0) .|> upreferred) === 1.0:2.0:5.0\n            @test @inferred(StepRange(1cm,1mm,2cm) .|> upreferred) === (1//100)m:(1//1000)m:(2//100)m\n\n            # float conversion, dimensionful\n            for r = [1eV:1eV:5eV, 1eV:1eV:5_000_000eV, 5_000_000eV:-1eV:-1eV, -123_456_789eV:2eV:987_654_321eV, (-11//12)eV:(1//3)eV:(11//4)eV]\n                for f = (mJ, upreferred)\n                    rf = @inferred(r .|> f)\n                    test_indices = length(r) ≤ 10_000 ? eachindex(r) : rand(eachindex(r), 10_000)\n                    @test eltype(rf) === typeof(f(zero(eltype(r))))\n                    @test all(≈(rf[i], f(r[i]); rtol=eps()) for i = test_indices)\n                end\n            end\n\n            # float conversion from unitless\n            r = 1:1:360\n            rf = °.(r)\n            @test all(≈(rf[i], °(r[i]); rtol=eps()) for i = eachindex(r))\n\n            # float conversion to unitless\n            r = (1:1:360)°\n            for f = (mrad, NoUnits, upreferred)\n                rf = f.(r)\n                @test eltype(rf) === typeof(f(zero(eltype(r))))\n                @test all(≈(rf[i], f(r[i]); rtol=eps()) for i = eachindex(r))\n            end\n\n            # exact conversion from and to unitless\n            @test rad.(1:1:360) === (1:1:360)rad\n            @test mrad.(1:1:360) === (1_000:1_000:360_000)mrad\n            @test upreferred.(1:1:360) === 1:1:360\n            @test NoUnits.((1:1:360)rad) === 1:1:360\n            @test upreferred.((1:1:360)rad) === 1:1:360\n            @test NoUnits.((1:2:5)mrad) === 1//1000:1//500:1//200\n            @test upreferred.((1:2:5)mrad) === 1//1000:1//500:1//200\n\n            @test @inferred((1:2:5) .* cm .|> mm .|> ustrip) === 10:20:50\n            @test @inferred((1f0:2f0:5f0) .* cm .|> mm .|> ustrip) === 10f0:20f0:50f0\n            @test @inferred(StepRange{typeof(1m),typeof(1cm)}(1m,1cm,2m) .|> ustrip) === 1:1//100:2\n            @test @inferred(StepRangeLen{typeof(1f0m)}(1.0m, 1.0cm, 101) .|> ustrip) === StepRangeLen{Float32}(1.0, 0.01, 101)\n            @test @inferred(StepRangeLen{typeof(1.0m)}(Base.TwicePrecision(1.0m), Base.TwicePrecision(1.0cm), 101) .|> ustrip) === StepRangeLen{Float64}(Base.TwicePrecision(1.0), Base.TwicePrecision(0.01), 101)\n            @test @inferred((1:0.1:1.0) .|> ustrip) == 1:0.1:1.0\n            @test @inferred((1m:0.1m:1.0m) .|> ustrip) == 1:0.1:1.0\n            @test @inferred(StepRange{typeof(0m),typeof(1cm)}(1m,1cm,2m) .|> ustrip) === 1:1//100:2\n            @test @inferred(StepRangeLen{typeof(1f0m)}(1.0m, 1.0cm, 101) .|> ustrip) === StepRangeLen{Float32}(1.0, 0.01, 101)\n            @test @inferred(StepRangeLen{typeof(1.0m)}(Base.TwicePrecision(1.0m), Base.TwicePrecision(1.0cm), 101) .|> ustrip) === StepRangeLen{Float64}(Base.TwicePrecision(1.0), Base.TwicePrecision(0.01), 101)\n            @test @inferred(StepRangeLen{typeof(1.0mm)}(Base.TwicePrecision(1.0m), Base.TwicePrecision(1.0cm), 101) .|> ustrip) === 1000.0:10.0:2000.0\n            @test ustrip.(1:0.1:1.0) == 1:0.1:1.0\n            @test ustrip.(1m:0.1m:1.0m) == 1:0.1:1.0\n        end\n        @testset \">> quantities and non-quantities\" begin\n            @test range(1, step=1m/mm, length=5) == 1:1000:4001\n            @test range(1, step=1mm/m, length=5) == (1//1):(1//1000):(251//250)\n            @test eltype(range(1, step=1m/mm, length=5)) == Int\n            @test eltype(range(1, step=1mm/m, length=5)) == Rational{Int}\n            @test range(1m/mm, step=1, length=5) == ((1//1):(1//1000):(251//250)) * m/mm\n            @test range(1mm/m, step=1, length=5) == (1:1000:4001) * mm/m\n            @test eltype(range(1m/mm, step=1, length=5)) == typeof((1//1)m/mm)\n            @test eltype(range(1mm/m, step=1, length=5)) == typeof(1mm/m)\n        end\n        @testset \">> complex\" begin\n            @test range((1+2im)m, step=(1+2im)m, length=5) == range(1+2im, step=1+2im, length=5) * m\n            @test range((1+2im)m, step=(1+2im)mm, length=5) == range(1//1+(2//1)im, step=1//1000+(1//500)im, length=5) * m\n            @test range((1.0+2.0im)m, stop=(3.0+4.0im)m, length=5) == LinRange(1.0+2.0im, 3.0+4.0im, 5) * m\n            @test range((1.0+2.0im)mm, stop=(3.0+4.0im)m, length=3) == LinRange(0.001+0.002im, 3.0+4.0im, 3) * m\n        end\n        @testset \">> step defaults to 1\" begin\n            @test range(1.0mm/m, length=5) == (1.0mm/m):(1000.0mm/m):(4001.0mm/m)\n            @test range((1+2im)mm/m, length=5) == range(1+2im, step=1000, length=5)*mm/m\n            @test_throws DimensionError range(1.0m, length=5)\n            @test_throws DimensionError range((1+2im)m, length=5)\n            @test (1mm/m):(5001mm/m) == (1:1000:5001) * mm/m\n            @test (1m/mm):(5m/mm) == (1//1:1//1000:5//1) * m/mm\n            @test (1mm/m):(1m/mm) == 1//1000:999001//1000\n            @test (1m/mm):(1mm/m) == 1000//1:999//1\n            @test (1.0mm/m):(5001mm/m) == (1.0:1000.0:5001.0) * mm/m\n            @test (1m/mm):(5.0m/mm) == (1.0:0.001:5.0) * m/mm\n            @test (1.0mm/m):(1m/mm) == 0.001:999.001\n            @test (1m/mm):(1.0mm/m) == 1000.0:1.0:999.0\n            @test_throws DimensionError (1m):(1m)\n            @test_throws DimensionError (1m):(1000cm)\n            @test_throws DimensionError (1m):(1s)\n            @test (1m/cm):1 == 100:99\n            @test (1m/cm):1000 == 100:1000\n            @test (1m/cm):1.0 == 100.0:99.0\n            @test (1.0m/cm):1000 == 100.0:1000.0\n            @test_throws DimensionError (1m):1\n            @test 1:(1m/mm) == 1:1000\n            @test 1000:(1m/mm) == 1000:1000\n            @test 1.0:(1m/mm) == 1.0:1000.0\n            @test 1000:(1.0m/mm) == 1000.0:1000.0\n            @test_throws DimensionError 1:(1m)\n        end\n        @static if VERSION ≥ v\"1.7\"\n            @testset \">> no start argument\" begin\n                @test range(stop=1.0m, step=2.0m, length=5) == -7.0m:2.0m:1.0m\n                @test range(stop=1.0mm, step=1.0m, length=5) == -3999.0mm:1000.0mm:1.0mm\n                @test range(stop=(1.0+2.0im)mm, step=(1.0+1.0im)m, length=5) == range(stop=1.0+2.0im, step=(1000+1000im), length=5)*mm\n                @test range(stop=1.0mm/m, length=5) == (-3999.0mm/m):(1000.0mm/m):(1.0mm/m)\n                @test range(stop=(1+2im)mm/m, length=5) == range(stop=1+2im, step=1000, length=5)*mm/m\n                @test range(stop=1.0mm/m, step=1, length=5) == (-3999.0mm/m):(1000.0mm/m):(1.0mm/m)\n                @test_throws DimensionError range(stop=1.0m, step=1V, length=5)\n                @test_throws DimensionError range(stop=(1+2im)m, step=1V, length=5)\n                @test_throws DimensionError range(stop=1.0m, length=5)\n                @test_throws DimensionError range(stop=(1+2im)m, length=5)\n                @test range(stop=1, step=1m/mm, length=5) == -3999:1000:1\n                @test range(stop=1, step=1mm/m, length=5) == (249//250):(1//1000):(1//1)\n                @test eltype(range(stop=1, step=1m/mm, length=5)) == Int\n                @test eltype(range(stop=1, step=1mm/m, length=5)) == Rational{Int}\n                @test range(stop=1m/mm, step=1, length=5) == ((249//250):(1//1000):(1//1)) * m/mm\n                @test range(stop=1mm/m, step=1, length=5) == (-3999:1000:1) * mm/m\n                @test eltype(range(stop=1m/mm, step=1, length=5)) == typeof((1//1)m/mm)\n                @test eltype(range(stop=1mm/m, step=1, length=5)) == typeof(1mm/m)\n                @test_throws ArgumentError range(step=1m, length=5)\n            end\n        end\n    end\n    @testset \"> Arrays\" begin\n        @testset \">> Array multiplication\" begin\n            # Quantity, quantity\n            @test @inferred([1m, 2m]' * [3m, 4m])    == 11m^2\n            @test @inferred([1m, 2m]' * [3/m, 4/m])  == 11\n            @test typeof([1m, 2m]' * [3/m, 4/m])     == Int\n            @test typeof([1m, 2V]' * [3/m, 4/V])     == Int\n            @test @inferred([1V,2V]*[0.1/m, 0.4/m]') == [0.1V/m 0.4V/m; 0.2V/m 0.8V/m]\n\n            # Probably broken as soon as we stopped using custom promote_op methods\n            @test_broken @inferred([1m, 2V]' * [3/m, 4/V])  == [11]\n            @test_broken @inferred([1m, 2V] * [3/m, 4/V]') ==\n                [3 4u\"m*V^-1\"; 6u\"V*m^-1\" 8]\n\n            # Quantity, number or vice versa\n            @test @inferred([1 2] * [3m,4m])         == [11m]\n            @test typeof([1 2] * [3m,4m])            == Array{typeof(1u\"m\"),1}\n            @test @inferred([3m 4m] * [1,2])         == [11m]\n            @test typeof([3m 4m] * [1,2])            == Array{typeof(1u\"m\"),1}\n\n            @test @inferred([1,2] * [3m,4m]')    == [3m 4m; 6m 8m]\n            @test typeof([1,2] * [3m,4m]')       == Array{typeof(1u\"m\"),2}\n            @test @inferred([3m,4m] * [1,2]')    == [3m 6m; 4m 8m]\n            @test typeof([3m,4m] * [1,2]')       == Array{typeof(1u\"m\"),2}\n\n            # re-allow vector*(1-row matrix), PR 20423\n            @test @inferred([1,2] * [3m 4m])     == [3m 4m; 6m 8m]\n            @test typeof([1,2] * [3m 4m])        == Array{typeof(1u\"m\"),2}\n            @test @inferred([3m,4m] * [1 2])     == [3m 6m; 4m 8m]\n            @test typeof([3m,4m] * [1 2])        == Array{typeof(1u\"m\"),2}\n        end\n        @testset \">> Element-wise multiplication\" begin\n            @test @inferred([1m, 2m, 3m] * 5)            == [5m, 10m, 15m]\n            @test typeof([1m, 2m, 3m] * 5)               == Array{typeof(1u\"m\"),1}\n            @test @inferred([1m, 2m, 3m] .* 5m)          == [5m^2, 10m^2, 15m^2]\n            @test typeof([1m, 2m, 3m] * 5m)              == Array{typeof(1u\"m^2\"),1}\n            @test @inferred(5m .* [1m, 2m, 3m])          == [5m^2, 10m^2, 15m^2]\n            @test typeof(5m .* [1m, 2m, 3m])             == Array{typeof(1u\"m^2\"),1}\n            @test @inferred(Matrix{Float64}(I, 2, 2)*V)  == [1.0V 0.0V; 0.0V 1.0V]\n            @test @inferred(V*Matrix{Float64}(I, 2, 2))  == [1.0V 0.0V; 0.0V 1.0V]\n            @test @inferred(Matrix{Float64}(I, 2, 2).*V) == [1.0V 0.0V; 0.0V 1.0V]\n            @test @inferred(V.*Matrix{Float64}(I, 2, 2)) == [1.0V 0.0V; 0.0V 1.0V]\n            @test @inferred([1V 2V; 0V 3V].*2)           == [2V 4V; 0V 6V]\n            @test @inferred([1V, 2V] .* [true, false])   == [1V, 0V]\n            @test @inferred([1.0m, 2.0m] ./ 3)           == [1m/3, 2m/3]\n            @test @inferred([1V, 2.0V] ./ [3m, 4m])      == [1V/(3m), 0.5V/m]\n\n            @test @inferred([1, 2]kg)                  == [1, 2] * kg\n            @test @inferred([1, 2]kg .* [2, 3]kg^-1)   == [2, 6]\n            @test @inferred([1, 2]/kg)                 == [1/kg, 2/kg]\n        end\n        @testset \">> Array addition\" begin\n            @test @inferred([1m, 2m] + [3m, 4m])     == [4m, 6m]\n            @test @inferred([1m, 2m] + [1m, 1cm])    == [2m, 201m//100]\n            @test @inferred([1m] + [1cm])            == [(101//100)*m]\n\n            # issue 127\n            b = [0.0, 0.0m]\n            @test b + b == b\n            @test b .+ b == b\n            @test eltype(b+b) === Number\n\n            # Dimensionless quantities\n            @test @inferred([1mm/m] + [1.0cm/m])     == [0.011]\n            @test typeof([1mm/m] + [1.0cm/m])        == Array{Float64,1}\n            @test @inferred([1mm/m] + [1cm/m])       == [11//1000]\n            @test typeof([1mm/m] + [1cm/m])          == Array{Rational{Int},1}\n            @test @inferred([1mm/m] + [2])           == [2001//1000]\n            @test typeof([1mm/m] + [2])              == Array{Rational{Int},1}\n            @test_throws DimensionError [1m] + [2V]\n            @test_throws DimensionError [1] + [1m]\n        end\n        @testset \">> Element-wise addition\" begin\n            @test @inferred(5m .+ [1m, 2m, 3m])      == [6m, 7m, 8m]\n            @test Any[1.0m, 2.0m] .+ 3.0m == [4.0m, 5.0m] # issue 557 (actually a bug in Julia 1.8.1)\n        end\n        @testset \">> Element-wise comparison\" begin\n            @test @inferred([0.0m, 2.0m] .< [3.0m, 2.0μm]) == BitArray([true,false])\n            @test @inferred([0.0m, 2.0m] .> [3.0m, 2.0μm]) == BitArray([false,true])\n            @test @inferred([0.0m, 0.0μm] .<= [0.0mm, 0.0mm]) == BitArray([true, true])\n            @test @inferred([0.0m, 0.0μm] .>= [0.0mm, 0.0mm]) == BitArray([true, true])\n            @test @inferred([0.0m, 0.0μm] .== [0.0mm, 0.0mm]) == BitArray([true, true])\n\n            # Want to make sure we play nicely with StaticArrays\n            for j in (<, <=, >, >=, ==)\n                @test @inferred(Base.promote_op(j, typeof(1.0m), typeof(1.0μm))) == Bool\n            end\n        end\n        @testset \">> isapprox on arrays\" begin\n            @test !isapprox([1.0m], [1.0V])\n            @test isapprox([1.0μm/m], [1e-6])\n            @test isapprox([1cm, 200cm], [0.01m, 2.0m])\n            @test !isapprox([1.0], [1.0m])\n            @test !isapprox([1.0m], [1.0])\n            @test isapprox([1.0m, NaN*m], [nextfloat(1.0)*m, NaN*m], nans=true)\n            @test !isapprox([1.0m, NaN*m], [nextfloat(1.0)*m, NaN*m], nans=false)\n            @test !isapprox([1.0m, 2.0m], [1.1m, 2.2m], rtol=0.05, atol=0.2m)\n            @test !isapprox([1.0m], [nextfloat(1.0)*m], atol=eps(0.1)*m)\n            @test isapprox([1.0u\"rad\"], [1.1]; atol=0.5u\"rad\")\n        end\n        @testset \">> Unit stripping\" begin\n            @test @inferred(ustrip([1u\"m\", 2u\"m\"])) == [1,2]\n            @test_deprecated ustrip([1,2])\n            @test ustrip.([1,2]) == [1,2]\n            @test typeof(ustrip([1u\"m\", 2u\"m\"])) <: Base.ReinterpretArray{Int,1}\n            @test typeof(ustrip(Diagonal([1,2]u\"m\"))) <: Diagonal{Int}\n            @test typeof(ustrip(Bidiagonal([1,2,3]u\"m\", [1,2]u\"m\", :U))) <:\n                Bidiagonal{Int}\n            @test typeof(ustrip(Tridiagonal([1,2]u\"m\", [3,4,5]u\"m\", [6,7]u\"m\"))) <:\n                Tridiagonal{Int}\n            @test typeof(ustrip(SymTridiagonal([1,2,3]u\"m\", [4,5]u\"m\"))) <:\n                SymTridiagonal{Int}\n        end\n        @testset \">> Linear algebra\" begin\n            @test istril(1m) === true\n            @test istril([1 1; 0 1]m) === false\n            @test istril([1 0; 1 1]K) === true\n            @test istril([1 0; 1 1]°C) === false\n            @test istril([1//1  -5463//20; 1//1 1//1]°C) === true\n            @test istriu(1m) === true\n            @test istriu([1 1; 0 1]m) === true\n            @test istriu([1 1; 0 1]K) === true\n            @test istriu([1 1; 0 1]°C) === false\n            @test istriu([1//1  1//1; -5463//20 1//1]°C) === true\n        end\n\n        @testset \">> Array initialization\" begin\n            Q = typeof(1u\"m\")\n            @test @inferred(zeros(Q, 2)) == [0, 0]u\"m\"\n            @test @inferred(zeros(Q, (2,))) == [0, 0]u\"m\"\n            @test @inferred(zeros(Q)[]) == 0u\"m\"\n            @test @inferred(fill!(similar([1.0, 2.0, 3.0], Q), zero(Q))) == [0, 0, 0]u\"m\"\n            @test @inferred(ones(Q, 2)) == [1, 1]u\"m\"\n            @test @inferred(ones(Q, (2,))) == [1, 1]u\"m\"\n            @test @inferred(ones(Q)[]) == 1u\"m\"\n            @test @inferred(fill!(similar([1.0, 2.0, 3.0], Q), oneunit(Q))) == [1, 1, 1]u\"m\"\n            @test size(rand(Q, 2)) == (2,)\n            @test size(rand(Q, 2, 3)) == (2,3)\n            @test eltype(@inferred(rand(Q, 2))) == Q\n            @test zero([1m, 2m]) == [0m, 0m]\n            @test zero(Quantity{Int,𝐋}[1m, 1mm]) == [0m, 0mm]\n            @test zero(Quantity{Int}[1m, 1s]) == [0m, 0s]\n            @test zero(Quantity[1m, 1s]) == [0m, 0s]\n            @test zero([1mm, missing]) == [0mm, 0mm]\n            @test zero(Union{typeof(0.0s),Missing}[missing]) == [0.0s]\n            if VERSION ≥ v\"1.9.0-rc1\"\n                @test zero(Union{Quantity{Int,𝐋},Missing}[1mm, missing]) == [0m, 0m]\n                @test zero(Union{Quantity{Float64,𝐋},Missing}[1.0mm, missing]) == [0.0m, 0.0m]\n                @test zero(Union{Quantity{Int,𝚯},Missing}[1°C, 2°F, missing]) == [0K, 0K, 0K]\n                @test zero(Vector{Union{Quantity{Float64,𝐋},Missing}}(undef, 1)) == [0.0m]\n            else\n                @test_broken zero(Union{Quantity{Int,𝐋},Missing}[1mm, missing]) == [0m, 0m]\n                @test_broken zero(Union{Quantity{Float64,𝐋},Missing}[1.0mm, missing]) == [0.0m, 0.0m]\n                @test_broken zero(Union{Quantity{Int,𝚯},Missing}[1°C, 2°F, missing]) == [0K, 0K, 0K]\n                @test_broken zero(Vector{Union{Quantity{Float64,𝐋},Missing}}(undef, 1)) == [0.0m]\n            end\n            @test_broken zero(Union{Quantity,Missing}[1m, 1mm]) == [0m, 0mm]\n            @test zero([1°C, 2°C]) == [0K, 0K]\n            @test zero(Quantity[1°C, 2°F]) == [0K, 0K]\n            @test zero(Union{typeof(0°C),Missing}[missing]) == [0K]\n            @test zero(Vector{typeof(big(1)mm)}(undef, 1)) == [big(0)mm]\n            @test zero(Vector{Union{typeof(big(1)mm),Missing}}(undef, 1)) == [big(0)mm]\n            @test zero(Vector{Quantity{Float64,𝐋}}(undef, 1)) == [0.0m]\n            @test_throws MethodError zero(Union{Quantity,Missing}[1m, 1s, missing])\n            @test_throws MethodError zero(Vector{Quantity}(undef, 1))\n            @test_throws MethodError zero(Vector{Union{Quantity,Missing}}(undef, 1))\n        end\n    end\nend\n\n@testset \"Display\" begin\n    withenv(\"UNITFUL_FANCY_EXPONENTS\" => false) do\n        @test string(typeof(1.0m/s)) == \"Quantity{Float64, 𝐋 𝐓^-1, FreeUnits{(m, s^-1), 𝐋 𝐓^-1, nothing}}\"\n        @test string(typeof(m/s)) == \"FreeUnits{(m, s^-1), 𝐋 𝐓^-1, nothing}\"\n        @test string(dimension(1u\"m/s\")) == \"𝐋 𝐓^-1\"\n        @test string(NoDims) == \"NoDims\"\n    end\n    @testset \":fancy_exponent IOContext property\" begin\n        @test sprint(io -> show(IOContext(io, :fancy_exponent => true), u\"m/s\")) == \"m s⁻¹\"\n        @test sprint(io -> show(IOContext(io, :fancy_exponent => false), u\"m/s\")) == \"m s^-1\"\n    end\n    @testset \"no Core.Box in show(::IO, ::Unitlike)\" begin\n        # Regression: the old implementation used a closure that reassigned an outer local, forcing the variable to be wrapped in a `Core.Box`. That hurt inference (variable inferred as `Core.Box` instead of `String`) and triggered \"local variable `first` is not defined\" reports from static analyzers like JET.\n        @test !any(==(Core.Box), only(code_typed(show, Tuple{IO, typeof(u\"m\")}; optimize=false)).first.slottypes)\n    end\nend\n\nstruct Foo <: Number end\nBase.show(io::IO, x::Foo) = print(io, \"1\")\nBase.show(io::IO, ::MIME\"text/plain\", ::Foo) = print(io, \"42.0\")\n\n@testset \"Show quantities\" begin\n    withenv(\"UNITFUL_FANCY_EXPONENTS\" => false) do\n        @test repr(1.0 * u\"m * s * kg^-1\") == \"1.0 m s kg^-1\"\n        @test repr(\"text/plain\", 1.0 * u\"m * s * kg^-1\") == \"1.0 m s kg^-1\"\n        @test repr(Foo() * u\"m * s * kg^-1\") == \"1 m s kg^-1\"\n        @test repr(\"text/plain\", Foo() * u\"m * s * kg^-1\") == \"42.0 m s kg^-1\"\n\n        # Complex quantities\n        @test repr((1+2im) * u\"m/s\") == \"(1 + 2im) m s^-1\"\n        @test repr(\"text/plain\", (1+2im) * u\"m/s\") == \"(1 + 2im) m s^-1\"\n\n        # Angular degree printing #253\n        @test sprint(show, 1.0°)       == \"1.0°\"\n        @test repr(\"text/plain\", 1.0°) == \"1.0°\"\n\n        # Concise printing of ranges\n        @test repr((1:10)*u\"kg/m^3\") == \"(1:10) kg m^-3\"\n        @test repr((1.0:0.1:10.0)*u\"kg/m^3\") == \"(1.0:0.1:10.0) kg m^-3\"\n        @test repr((1:10)*°) == \"(1:10)°\"\n        @test repr(range(1.0+2.0im, length=5)*u\"m\") == \"(1.0 + 2.0im:1.0 + 0.0im:5.0 + 2.0im) m\"\n        @test repr(range(1+2im, step=1+1im, length=5)*u\"m\") == \"(1 + 2im:1 + 1im:5 + 6im) m\"\n        @test repr(StepRange((1//1)u\"m\", 1u\"cm\", (2//1)u\"m\")) == \"(1//1:1//100:2//1) m\"\n        @test repr(StepRangeLen(1.0u\"m\", 1.0u\"cm\", 101)) == \"(1.0:0.01:2.0) m\"\n\n        # Concise printing of affine ranges with mixed step unit\n        @test repr(StepRange(1u\"°C\", 1u\"K\", 3u\"°C\")) == \"(1:3) °C\"\n        @test repr(StepRange(1u\"°C\", 1.0u\"K\", 3u\"°C\")) == \"(1:3) °C\"\n        @test repr(StepRange(1.0u\"°C\", 1u\"K\", 3.0u\"°C\")) == \"(1.0:1.0:3.0) °C\"\n        @test repr(StepRange(1.0u\"°C\", 1.0u\"K\", 3.0u\"°C\")) == \"(1.0:1.0:3.0) °C\"\n        @test repr(StepRange((0//1)u\"°F\", 1u\"K\", (9//1)u\"°F\")) == \"(0//1:9//5:9//1) °F\"\n        @test repr(StepRangeLen{typeof(1.0u\"°C\"),typeof(1.0u\"°C\"),typeof(1u\"K\")}(1.0u\"°C\", 1u\"K\", 3, 1)) == \"(1.0:1.0:3.0) °C\"\n        @test repr(StepRangeLen{typeof(1u\"°C\"),typeof(1u\"°C\"),typeof(1u\"K\")}(1u\"°C\", 1u\"K\", 3, 1)) == \"(1:1:3) °C\"\n        @test repr(StepRangeLen{typeof(1.0u\"°F\"),typeof(1.0u\"°F\"),typeof(1u\"K\")}(0.0u\"°F\", 1u\"K\", 6)) == \"(0.0:1.8:9.0) °F\"\n    end\n    withenv(\"UNITFUL_FANCY_EXPONENTS\" => true) do\n        @test repr(1.0 * u\"m * s * kg^(-1//2)\") == \"1.0 m s kg⁻¹ᐟ²\"\n    end\n    withenv(\"UNITFUL_FANCY_EXPONENTS\" => nothing) do\n        @test repr(1.0 * u\"m * s * kg^(-1//2)\") ==\n            (Sys.isapple() ? \"1.0 m s kg⁻¹ᐟ²\" : \"1.0 m s kg^-1/2\")\n    end\n    @test Base.alignment(stdout, (1//3)m)  == Base.alignment(stdout, 1//3) .+ (0, 2)\n    @test Base.alignment(stdout, (2+3im)m) == Base.alignment(stdout, 2+3im) .+ (1, 3)\n    @test Base.alignment(stdout, 3.0dB)    == Base.alignment(stdout, 3.0) .+ (0, 3)\n    @test Base.alignment(stdout, 3.0dBm)   == Base.alignment(stdout, 3.0) .+ (0, 4)\n    @test Base.alignment(stdout, 3.0dB*s)  == Base.alignment(stdout, 3.0) .+ (1, 6)\n    @test Base.alignment(stdout, 3.0dBm*s) == Base.alignment(stdout, 3.0) .+ (1, 7)\nend\n\nVERSION ≥ v\"1.9.0\" && @testset \"printf\" begin\n    @test (@sprintf \"%f %d %.2f %05d\" 1.23u\"m\" 123.4u\"°\" 0.1234u\"W\" 12.34u\"km\") == \"1.230000 m 123° 0.12 W 00012 km\"\nend\n\nisdefined(Base, :get_extension) && @testset \"Latexify extension\" begin\n\nfunction unitfullatexifytest(val, mathrmexpected, siunitxexpected, siunitxsimpleexpected)\n    @test latexify(val; fmt=FancyNumberFormatter()) ==\n        LaTeXString(replace(mathrmexpected, \"\\r\\n\" => \"\\n\"))\n    @test latexify(val; fmt=SiunitxNumberFormatter()) ==\n        LaTeXString(replace(siunitxexpected, \"\\r\\n\" => \"\\n\"))\n    @test latexify(val; fmt=SiunitxNumberFormatter(simple=true)) ==\n        LaTeXString(replace(siunitxsimpleexpected, \"\\r\\n\"=>\"\\n\"))\nend\n\n@testset \"Latexify units\" begin\n    unitfullatexifytest(\n        u\"H*J/kg\",\n        raw\"$\\mathrm{H}\\,\\mathrm{J}\\,\\mathrm{kg}^{-1}$\",\n        raw\"\\unit{\\henry\\joule\\per\\kilo\\gram}\",\n        raw\"\\unit{H.J.kg^{-1}}\",\n    )\n    unitfullatexifytest(\n        24.7e9u\"Gm/s^2\",\n        raw\"$2.47 \\cdot 10^{10}\\,\\mathrm{Gm}\\,\\mathrm{s}^{-2}$\",\n        raw\"\\qty{2.47e10}{\\giga\\meter\\per\\second\\tothe{2}}\",\n        raw\"\\qty{2.47e10}{Gm.s^{-2}}\",\n    )\n    unitfullatexifytest(\n        u\"percent\", raw\"$\\mathrm{\\%}$\", raw\"\\unit{\\percent}\", raw\"\\unit{\\%}\"\n    )\n    unitfullatexifytest(\n        2u\"°C\", raw\"$2\\,\\mathrm{^\\circ C}$\", raw\"\\qty{2}{\\celsius}\", raw\"\\qty{2}{\\celsius}\"\n    )\n    unitfullatexifytest(\n        1u\"°\", raw\"$1\\mathrm{^{\\circ}}$\", raw\"\\qty{1}{\\degree}\", raw\"\\qty{1}{\\degree}\"\n    )\n    unitfullatexifytest(\n        [1, 2, 3]*m,\n        raw\"\"\"\n        \\begin{equation}\n        \\left[\n        \\begin{array}{c}\n        1 \\\\\n        2 \\\\\n        3 \\\\\n        \\end{array}\n        \\right]\\,\\mathrm{m}\n        \\end{equation}\n        \"\"\",\n        raw\"\"\"\n        \\begin{equation}\n        \\left[\n        \\begin{array}{c}\n        \\num{1} \\\\\n        \\num{2} \\\\\n        \\num{3} \\\\\n        \\end{array}\n        \\right]\\,\\unit{\\meter}\n        \\end{equation}\n        \"\"\",\n        raw\"\"\"\n        \\begin{equation}\n        \\left[\n        \\begin{array}{c}\n        \\num{1} \\\\\n        \\num{2} \\\\\n        \\num{3} \\\\\n        \\end{array}\n        \\right]\\,\\unit{m}\n        \\end{equation}\n        \"\"\",\n    )\n    unitfullatexifytest((1,2,3).*m,\n        raw\"\"\"\n        \\begin{equation}\n        \\left[\n        \\begin{array}{c}\n        1 \\\\\n        2 \\\\\n        3 \\\\\n        \\end{array}\n        \\right]\\,\\mathrm{m}\n        \\end{equation}\n        \"\"\",\n        raw\"\\qtylist{1;2;3}{\\meter}\",\n        raw\"\\qtylist{1;2;3}{m}\",\n    )\n\n    @test latexify(24.7e9u\"Gm/s^2\"; fmt=\"%.1e\") ==\n        L\"$2.5e+10\\,\\mathrm{Gm}\\,\\mathrm{s}^{-2}$\"\n    @test latexify(5.9722e24u\"kg\"; fmt=SiunitxNumberFormatter(version=2)) ==\n        raw\"\\SI{5.9722e24}{\\kilo\\gram}\"\n    @test latexify(u\"eV\"; fmt=SiunitxNumberFormatter(version=2)) == raw\"\\si{\\electronvolt}\"\nend\n\n@testset \"permode\" begin\n    p = 5u\"m^3*s^2/H/kg^4\"\n    @test latexify(p) == LaTeXString(\n        raw\"$5\\,\\mathrm{m}^{3}\\,\\mathrm{s}^{2}\\,\\mathrm{kg}^{-4}\\,\\mathrm{H}^{-1}$\"\n    )\n    @test latexify(p; permode=:power) == LaTeXString(\n        raw\"$5\\,\\mathrm{m}^{3}\\,\\mathrm{s}^{2}\\,\\mathrm{kg}^{-4}\\,\\mathrm{H}^{-1}$\"\n    )\n    @test latexify(p; permode=:slash) == LaTeXString(\n        raw\"$5\\,\\mathrm{m}^{3}\\,\\mathrm{s}^{2}\\,/\\,\\mathrm{kg}^{4}\\,\\mathrm{H}$\"\n    )\n    @test latexify(p; permode=:frac) == LaTeXString(\n        raw\"$5\\,\\frac{\\mathrm{m}^{3}\\,\\mathrm{s}^{2}}{\\mathrm{kg}^{4}\\,\\mathrm{H}}$\"\n    )\n    @test latexify(p; permode=:frac, fmt=SiunitxNumberFormatter()) ==\n        latexify(p; fmt=SiunitxNumberFormatter())\n    @test latexify(m; permode=:frac) == latexify(m)\n    @test latexify(u\"m^-1\"; permode=:frac) == LaTeXString(raw\"$\\frac{1}{\\mathrm{m}}$\")\n    @test_throws ErrorException latexify(p; permode=:wrong)\nend\n\n@testset \"Labels\" begin\n    @test latexify(\"x\", m) == raw\"$x\\;\\left/\\;\\mathrm{m}\\right.$\"\n    @test latexify(\"x\", m; labelformat=:slash) == raw\"$x\\;\\left/\\;\\mathrm{m}\\right.$\"\n    @test latexify(\"x\", m; labelformat=:square) == raw\"$x\\;\\left[\\mathrm{m}\\right]$\"\n    @test latexify(\"x\", m; labelformat=:round) == raw\"$x\\;\\left(\\mathrm{m}\\right)$\"\n    @test latexify(\"x\", m; labelformat=:frac) == raw\"$\\frac{x}{\\mathrm{m}}$\"\n    Latexify.set_default(labelformat=:square)\n    @test latexify(\"x\", m) == raw\"$x\\;\\left[\\mathrm{m}\\right]$\"\n    @test_throws \"Unknown labelformat\" latexify(\"x\", m; labelformat=:wrong)\n    # Issue 816\n    @test latexify(\"T\", u\"°C\"; labelformat=:slash) == raw\"$T\\;\\left/\\;\\mathrm{^\\circ C}\\right.$\"\n    @test latexify(\"T\", u\"°F\"; labelformat=:slash) == raw\"$T\\;\\left/\\;\\mathrm{^\\circ F}\\right.$\"\nend\n\n@testset \"Parentheses\" begin\n    @test @latexify($(3u\"mm\")^2 - 4 * $(2u\"mm^2\")) ==\n        raw\"$\\left( 3\\,\\mathrm{mm} \\right)^{2} - 4 \\cdot 2\\,\\mathrm{mm}^{2}$\"\nend\nend\n\n\n@testset \"DimensionError message\" begin\n    function errorstr(e)\n        b = IOBuffer()\n        Base.showerror(b,e)\n        String(take!(b))\n    end\n    @test errorstr(DimensionError(1u\"m\",2)) ==\n        \"DimensionError: 1 m and 2 are not dimensionally compatible.\"\n    @test errorstr(DimensionError(1u\"m\",NoDims)) ==\n        \"DimensionError: 1 m and NoDims are not dimensionally compatible.\"\n    @test errorstr(DimensionError(u\"m\",2)) ==\n        \"DimensionError: m and 2 are not dimensionally compatible.\"\nend\n\n@testset \"Logarithmic quantities\" begin\n    @testset \"> Explicit construction\" begin\n        @testset \">> Level\" begin\n            # Outer constructor\n            @test Level{Decibel,1}(2) isa Level{Decibel,1,Int}\n            @test_throws DimensionError Level{Decibel,1}(2V)\n            @test_throws DimensionError Level{Decibel,1V}(2)\n            @test_throws InexactError Level{Decibel,1}(1+1im)\n            @test_throws DomainError Level{Decibel,1+0im}(2)\n            @test_throws DomainError Level{Decibel,(1+0im)V}(2V)\n            @test_throws DomainError Level{Decibel,(1+1im)V}(2V)\n\n            # Inner constructor\n            @test Level{Decibel,1,Int}(2) === Level{Decibel,1}(2)\n            @test Level{Decibel,1,Int}(2) === Level{Decibel,1,Int}(2.0)\n            @test Level{Decibel,1,Int}(2) === Level{Decibel,1,Int}(2+0im)\n            @test_throws DimensionError Level{Decibel,1,typeof(2V)}(2V)\n            @test_throws DimensionError Level{Decibel,1V,Int}(2)\n            @test_throws TypeError Level{Decibel,1,Complex{Int}}(1+1im)\n            @test_throws TypeError Level{Decibel,1V,typeof((1+1im)V)}((1+1im)V)\n            @test_throws DomainError Level{Decibel,1+0im,Int}(2)\n            @test_throws DomainError Level{Decibel,(1+0im)V,typeof(2V)}(2V)\n        end\n\n        @testset \">> Gain\" begin\n            @test Gain{Decibel}(1) isa Gain{Decibel,:?,Int}\n            @test Gain{Decibel,:rp}(1) isa Gain{Decibel,:rp,Int}\n            @test_throws MethodError Gain{Decibel}(1V)\n            @test_throws MethodError Gain{Decibel,:?}(1V)\n            @test_throws TypeError Gain{Decibel,:?,typeof(1V)}(1V)\n        end\n    end\n\n    @testset \"> Implicit construction\" begin\n        @testset \">> Level\" begin\n            @test 20*dBm == (@dB 100mW/mW) == (@dB 100mW/1mW) == dB(100mW,mW) == dB(100mW,1mW)\n            @test 20*dBV == (@dB 10V/V) == (@dB 10V/1V) == dB(10V,V) == dB(10V,1V)\n            @test_throws ArgumentError @dB 10V/V true\n        end\n\n        @testset \">> Gain\" begin\n            @test_throws LoadError @eval @dB 10\n            @test 20*dB === dB*20\n        end\n\n        @testset \">> MixedUnits\" begin\n            @test dBm === MixedUnits{Level{Decibel, 1mW}}()\n            @test dBm/Hz === MixedUnits{Level{Decibel, 1mW}}(Hz^-1)\n        end\n    end\n\n    @testset \"> Unit and dimensional analysis\" begin\n        @testset \">> Level\" begin\n            @test dimension(1dBm) === dimension(1mW)\n            @test dimension(typeof(1dBm)) === dimension(1mW)\n            @test dimension(1dBV) === dimension(1V)\n            @test dimension(typeof(1dBV)) === dimension(1V)\n            @test dimension(1dB) === NoDims\n            @test dimension(typeof(1dB)) === NoDims\n            @test dimension(@dB 3V/2.14V) === dimension(1V)\n            @test dimension(typeof(@dB 3V/2.14V)) === dimension(1V)\n            @test logunit(1dBm) === dBm\n            @test logunit(typeof(1dBm)) === dBm\n        end\n\n        @testset \">> Gain\" begin\n            @test logunit(3dB) === dB\n            @test logunit(3dB_rp) === dB_rp\n            @test logunit(3dB_p) === dB_p\n            @test logunit(typeof(3dB)) === dB\n            @test logunit(typeof(3dB_rp)) === dB_rp\n            @test logunit(typeof(3dB_p)) === dB_p\n        end\n\n        @testset \">> Quantity{<:Level}\" begin\n            @test dimension(1dBm/Hz) === dimension(1mW/Hz)\n            @test dimension(typeof(1dBm/Hz)) === dimension(1mW/Hz)\n            @test dimension(1dB/Hz) === dimension(Hz^-1)\n            @test dimension(typeof(1dB/Hz)) === dimension(Hz^-1)\n            @test dimension((@dB 3V/2.14V)/Hz) === dimension(1V/Hz)\n            @test dimension(typeof((@dB 3V/2.14V)/Hz)) === dimension(1V/Hz)\n        end\n    end\n\n    @testset \"> Conversion\" begin\n        @test float(3dB) == 3.0dB\n        @test float(@dB 3V/1V) === @dB 3.0V/1V\n\n        for x = (20, 20.0, 20//1)\n            for u = (dB, dB/m, dBV, dBV/m)\n                @test @inferred(big(x*u)) == big(x)*u\n                @test typeof(big(x*u)) == typeof(big(x)*u)\n                @test big(typeof(x*u)) == typeof(big(x)*u)\n            end\n        end\n\n        @test uconvert(V, (@dB 3V/2.14V)) === 3V\n        @test uconvert(V, (@dB 3V/1V)) === 3V\n        @test uconvert(mW/Hz, 0dBm/Hz) == 1mW/Hz\n        @test uconvert(mW/Hz, (@dB 1mW/mW)/Hz) === 1mW/Hz\n        @test uconvert(dB, 1Np) ≈ 8.685889638065037dB\n        @test uconvert(dB, 10dB*m/mm) == 10000dB\n\n        @test convert(typeof(1.0dB), 1Np) ≈ 8.685889638065037dB\n        @test convert(typeof(1.0dBm), 1W) == 30.0dBm\n        @test_throws DimensionError convert(typeof(1.0dBm), 1V)\n        @test convert(typeof(3dB), 3dB) === 3dB\n        @test convert(typeof(3.0dB), 3dB) === 3.0dB\n        @test convert(Float64, 0u\"dBFS\") === 1.0\n\n        @test_throws ErrorException convert(Float64, u\"10dB\")\n        @test convert(Float64, u\"10dB_p\") === 10.0\n        @test convert(Float64, u\"20dB_rp\") === 10.0\n\n        @test_throws ErrorException convert(typeof(1.0dB/s), 5.0Hz)\n        @test convert(typeof(1.0dB_p/s), 100.0Hz) === 20.0dB_p/s\n        @test convert(typeof(1.0dB_rp/s), 100.0Hz) === 40.0dB_rp/s\n\n        @test_throws ErrorException convert(typeof(1.0dB/rad), 5.0)\n        @test convert(typeof(1.0dB_p/rad), 100.0) === 20.0dB_p/rad\n        @test convert(typeof(1.0dB_rp/rad), 100.0) === 40.0dB_rp/rad\n\n        @test convert(typeof(1.0m/cm), 40.0dB_rp) === 1.0m/cm\n        @test convert(typeof(1.0dB_p/s), 1.0dB_p/s) === 1.0dB_p/s\n\n        # This currently (and unnecessarily) involves a conversion to linear and back to logarithmic.\n        # This is lossy due to floating-point, therefore broken.\n        @test_broken convert(Quantity{typeof(1.0dB_rp), NoDims, typeof(Unitful.NoUnits)}, 1dB_rp) === 1.0dB_rp\n        @test_broken convert(typeof(1.0dB_p/s), 1dB_p/s) === 1.0dB_p/s # conversion to linear and back to logarithmic → lossy due to floating-point\n        @test isapprox(convert(typeof(1.0dB_p/s), 1dB_p/s), 1.0dB_p/s, rtol = 1e-3, atol=0/s)\n\n        # Wrongly throwing DimensionError\n        @test_broken convert(typeof(1.0dBm/s), 5.0mW*Hz) === @dB(5.0mW/1mW)/s\n        @test convert(typeof(1.0u\"dBFS/rad\"), 100.0) === @dB(100.0/1, true)/rad\n        @test_broken convert(typeof(1.0dBm/rad), 20.0dBm) === @dB(100.0mW/1mW)/rad\n        @test convert(typeof(1.0u\"dBFS/rad\"), 5.0u\"dBFS\") === 5.0u\"dBFS/rad\"\n        @test_broken convert(Quantity{typeof(1.0dBm), dimension(Unitful.mW), typeof(Unitful.NoUnits)}, 5.0dBm) === Quantity{typeof(1.0dBm), dimension(Unitful.mW), typeof(Unitful.NoUnits)}(5.0dBm)\n        @test convert(typeof(1.0m/cm), 40.0u\"dBFS\") === 1.0m/cm\n\n        for L = (40u\"dB_rp\", 20u\"dB_p\", 40u\"dBFS\")\n            for U = (NoUnits, FixedUnits(NoUnits), ContextUnits(NoUnits, m/mm))\n                @test convert(Quantity{Int,NoDims,typeof(U)}, L) === Quantity{Int,NoDims,typeof(U)}(100)\n                @test convert(Quantity{Int,NoDims,typeof(U)}, L/rad) === Quantity{Int,NoDims,typeof(U)}(100)\n            end\n            @test convert(Quantity{Int}, L) === Quantity{Int,NoDims,typeof(NoUnits)}(100)\n            @test convert(Quantity{Int}, L/rad) === 100/rad\n            @test convert(Quantity{Int,NoDims}, L) === Quantity{Int,NoDims,typeof(NoUnits)}(100)\n            @test convert(Quantity{Int,NoDims}, L/rad) === 100/rad\n        end\n\n        @test isapprox(uconvertrp(NoUnits, 6.02dB), 2.0, atol=0.001)\n        @test uconvertrp(NoUnits, 1Np) ≈ MathConstants.e\n        @test uconvertrp(Np, MathConstants.e) == 1Np\n        @test uconvertrp(NoUnits, 1) == 1\n        @test uconvertrp(NoUnits, 20dB) == 10\n        @test uconvertrp(dB, 10) == 20dB\n        @test isapprox(uconvertp(NoUnits, 3.01dB), 2.0, atol=0.001)\n        @test uconvertp(NoUnits, 1Np) == (MathConstants.e)^2\n        @test uconvertp(Np, (MathConstants.e)^2) == 1Np\n        @test uconvertp(NoUnits, 1) == 1\n        @test uconvertp(NoUnits, 20dB) == 100\n        @test uconvertp(dB, 100) == 20dB\n\n        @test linear(@dB(1mW/mW)/Hz) === 1mW/Hz\n        @test linear(@dB(1.4V/2.8V)/s) === 1.4V/s\n\n        @test convert(Gain{Decibel}, 0dB_rp) === 0dB_rp\n        @test convert(Gain{Neper}, 10dB) ≈ 1.151292546Np\n        @test convert(Gain{Decibel,:?}, 0dB_rp) === 0dB\n        @test convert(Gain{Neper,:?}, 10dB) ≈ 1.151292546Np\n        @test convert(Gain{Decibel,:?,Float32}, 0dB_rp) === 0.0f0*dB\n        @test convert(Gain{Neper,:rp,Float32}, 10dB) === 1.1512926f0*Np_rp\n    end\n\n    @testset \"> Equality\" begin\n        @testset \">> Level\" begin\n            @test big(3.0)dBm == big(3.0)dBm\n            @test isequal(big(3.0)dBm, big(3.0)dBm)\n            @test hash(big(3.0)dBm) == hash(big(3.0)dBm)\n\n            @test @dB(3.0V/2.0V) == @dB(3V/V)\n            @test isequal(@dB(3.0V/2.0V), @dB(3V/V))\n            @test hash(@dB(3.0V/2.0V)) == hash(@dB(3V/V))\n        end\n\n        @testset \">> Gain\" begin\n            @test 3dB == (3//1)dB\n            @test isequal(3dB, (3//1)dB)\n            @test_broken hash(3dB) == hash((3//1)dB)\n\n            @test big(3)dB == big(3)dB\n            @test isequal(big(3)dB, big(3)dB)\n            @test_broken hash(big(3)dB) == hash(big(3)dB)\n\n            @test 0.0dB == -0.0dB\n            @test !isequal(0.0dB, -0.0dB)\n            @test hash(0.0dB) != hash(-0.0dB)\n        end\n\n        @test !(20dBm == 20dB)\n        @test !(20dB == 20dBm)\n        @test !(20dBm == 20dBV)\n        @test !(20dBV == 20dBm)\n    end\n\n    @testset \"> Addition and subtraction\" begin\n        @testset \">> Level\" begin\n            @test isapprox(10dBm + 10dBm, 13dBm; atol=0.02dBm)\n            @test !isapprox(10dBm + 10dBm, 13dBm; atol=0.00001dBm)\n            @test isapprox(13dBm, 20mW; atol = 0.1mW)\n            @test @dB(10mW/mW) + 1mW === 11mW\n            @test 1mW + @dB(10mW/mW) === 11mW\n            @test @dB(10mW/mW) + @dB(90mW/mW) === @dB(100mW/mW)\n            @test (@dB 10mW/3mW) + (@dB 11mW/2mW) === 21mW\n            @test (@dB 10mW/3mW) + 2mW === 12mW\n            @test (@dB 10mW/3mW) + 1W === 101u\"kg*m^2/s^3\"//100\n            @test 20dB + 20dB == 40dB\n            @test 20dB + 20.2dB == 40.2dB\n            @test 1Np + 1.5Np == 2.5Np\n            @test_throws DimensionError (1dBm + 1dBV)\n            @test_throws DimensionError (1dBm + 1V)\n        end\n\n        @testset \">> Gain\" begin\n            for op in (:+, :*)\n                @test @eval ($op)(20dB, 10dB)      === 30dB\n                @test @eval ($op)(20dB_rp, 10dB)   === 30dB_rp\n                @test @eval ($op)(20dB, 10dB_rp)   === 30dB_rp\n                @test @eval ($op)(20dB_p, 10dB)    === 30dB_p\n                @test @eval ($op)(20dB, 10dB_p)    === 30dB_p\n                @test @eval ($op)(20dB_rp, 10dB_p) === 30dB\n                @test @eval ($op)(20dB_p, 10dB_rp) === 30dB\n                @test_throws ErrorException @eval ($op)(1dB, 1Np) # no promotion\n                @test_throws ErrorException @eval ($op)(1dB_rp, 1Np)\n            end\n            for op in (:-, :/)\n                @test @eval ($op)(20dB, 10dB)      === 10dB\n                @test @eval ($op)(20dB_rp, 10dB)   === 10dB_rp\n                @test @eval ($op)(20dB, 10dB_rp)   === 10dB_rp\n                @test @eval ($op)(20dB_p, 10dB)    === 10dB_p\n                @test @eval ($op)(20dB, 10dB_p)    === 10dB_p\n                @test @eval ($op)(20dB_rp, 10dB_p) === 10dB\n                @test @eval ($op)(20dB_p, 10dB_rp) === 10dB\n                @test_throws ErrorException @eval ($op)(1dB, 1Np) # no promotion\n                @test_throws ErrorException @eval ($op)(1dB_rp, 1Np)\n            end\n        end\n\n        @testset \">> Level, meet Gain\" begin\n            for op in (:+, :*)\n                @test @eval ($op)(10dBm, 30dB)    == 40dBm\n                @test @eval ($op)(30dB, 10dBm)    == 40dBm\n                @test @eval ($op)(10dBm, 30dB_rp) == 40dBm\n                @test @eval ($op)(30dB_rp, 10dBm) == 40dBm\n                @test @eval ($op)(10dBm, 30dB_p)  == 40dBm\n                @test @eval ($op)(30dB_p, 10dBm)  == 40dBm\n                @test @eval ($op)(0Np, 3dBm)      == 3dBm\n            end\n            for op in (:-, :/)\n                @test @eval ($op)(10dBm, 30dB)    == -20dBm\n                @test @eval ($op)(10dBm, 30dB_rp) == -20dBm\n                @test @eval ($op)(10dBm, 30dB_p) == -20dBm\n                @test @eval isapprox(($op)(10dBm, 1Np), 1.314dBm; atol=0.001dBm)\n                @test @eval isapprox(($op)(10dBm, 1Np_rp), 1.314dBm; atol=0.001dBm)\n                @test @eval isapprox(($op)(10dBm, 1Np_p), 1.314dBm; atol=0.001dBm)\n\n                # cannot subtract Levels from Gains\n                @test_throws ArgumentError @eval ($op)(10dB, 30dBm)\n                @test_throws ArgumentError @eval ($op)(10dB_rp, 30dBm)\n                @test_throws ArgumentError @eval ($op)(10dB_p, 30dBm)\n                @test_throws ArgumentError @eval ($op)(1Np, 10dBm)\n                @test_throws ArgumentError @eval ($op)(1Np_rp, 10dBm)\n                @test_throws ArgumentError @eval ($op)(1Np_p, 10dBm)\n            end\n        end\n    end\n\n    @testset \"> Multiplication and division\" begin\n        @testset \">> Level\" begin\n            @test (0dBm) * 10 == (10dBm)\n            @test @dB(10V/V)*10 == 100V\n            @test @dB(10V/V)/20 == 0.5V\n            @test 10*@dB(10V/V) == 100V\n            @test 10/@dB(10V/V) == 1V^-1\n            @test (0dBm) * (1W) == 1*mW*W\n            @test (1W) * (0dBm) == 1*W*mW\n            @test 100*((0dBm)/s) == (20dBm)/s\n            @test isapprox((3.01dBm)*(3.01dBm), 4mW^2, atol=0.01mW^2)\n            @test typeof((1dBm * big\"2\").val.val) == BigFloat\n            @test 10dBm/10Hz == 1mW/Hz\n            @test 10Hz/10dBm == 1Hz/mW\n            @test true*3dBm == 3dBm\n            @test false*3dBm == -Inf*dBm\n            @test 3dBm*true == 3dBm\n            @test 3dBm*false == -Inf*dBm\n            @test (0dBV)*(1Np) ≈ 8.685889638dBV\n            @test dBm/5 ≈ 0.2dBm\n            @test linear((@dB 3W/W)//3) === 1W//1\n            @test (@dB 3W/W)//(@dB 3W/W) === 1//1\n        end\n\n        @testset \">> Gain\" begin\n            @test 3dB * 2 === 6dB\n            @test 2 * 3dB === 6dB\n            @test 3dB_rp * 2 === 6dB_rp\n            @test 2 * 3dB_rp === 6dB_rp\n            @test 3dB_p * 2 === 6dB_p\n            @test 2 * 3dB_p === 6dB_p\n            @test 20dB * 1mW == 100mW\n            @test 1mW * 20dB == 100mW\n            @test 3dB * 2.1 ≈ 6.3dB\n            @test 3dB * false == 0*dB\n            @test false * 3dB == 0*dB\n            @test 1V * 20dB == 10V\n            @test 20dB * 1V == 10V\n            @test 10J * 10dB == 100J\n            @test 10W/m^3 * 10dB == 100W/m^3\n        end\n\n        @testset \">> MixedUnits\" begin\n            @test_throws ArgumentError dB*dB\n            @test_throws ArgumentError dB/Np\n            @test dB/dB === NoUnits\n            @test (dB*m)/(dB*s) === m/s\n            @test m*dB === dB*m\n            @test [1,2,3]u\"dB\" == u\"dB\"*[1,2,3]\n        end\n    end\n\n    @testset \"> Comparisons\" begin\n        @test 3dB < 5dB\n        @test 3dBm < 5dBm\n        @test_throws MethodError 3dB < 5dBm\n    end\n\n    @testset \"> zero, one\" begin\n        @test zero(3dB) === 0dB\n        @test zero(3dB_rp) === 0dB_rp\n        @test zero(typeof(3dB)) === 0dB\n        @test one(3dB) === 0dB\n        @test one(3dB_rp) === 0dB_rp\n        @test one(typeof(3dB)) === 0dB\n\n        @test zero(3dBm) === (-Inf)*dBm\n        @test zero(typeof(3dBm)) === (-Inf)*dBm\n        @test one(3dBm) === 1.0\n        @test one(typeof(3dBm)) === 1.0\n        @test one(@dB 3mW/1mW) === 1\n    end\n\n    @testset \"> Unit stripping\" begin\n        @test ustrip(500.0Np) === 500.0\n        @test ustrip(20dB/Hz) === 20\n        @test ustrip(20dB) === 20\n        @test ustrip(20dB_rp) === 20\n        @test ustrip(13dBm) ≈ 13\n        @test ustrip(missing) === missing\n    end\n\n    @testset \"> Display\" begin\n        withenv(\"UNITFUL_FANCY_EXPONENTS\" => false) do\n            @test repr(3u\"dB/Hz\") == \"[3 dB] Hz^-1\"\n            @test repr(\"text/plain\", 3u\"dB/Hz\") == \"[3 dB] Hz^-1\"\n        end\n        @test Unitful.abbr(3u\"dBm\") == \"dBm\"\n        @test Unitful.abbr(@dB 3V/1.241V) == \"dB (1.241 V)\"\n        @test string(360°) == \"360°\"\n    end\n\n    @testset \"> Thanks for signing up for Log Facts!\" begin\n        @test_throws ErrorException 20dB == 100\n        @test 20dBm ≈ 100mW\n        @test 20dBV ≈ 10V\n        @test 40dBV ≈ 100V\n\n        # Maximum sound pressure level is a full swing of atmospheric pressure\n        @test isapprox(uconvert(dBSPL, 1u\"atm\"), 194dBSPL, atol=0.1dBSPL)\n    end\nend\n\n@testset \"Output ordered by unit exponent\" begin\n    ordered = Unitful.sortexp(u\"J*mol^-1*K^-1\")\n    @test typeof(ordered[1]) <: Unitful.Unit{:Joule,<:Any}\n    @test typeof(ordered[2]) <: Unitful.Unit{:Kelvin,<:Any}\n    @test typeof(ordered[3]) <: Unitful.Unit{:Mole,<:Any}\n\n    ordered = Unitful.sortexp(u\"mol*J^-1*K^-1\")\n    @test typeof(ordered[1]) <: Unitful.Unit{:Mole,<:Any}\n    @test typeof(ordered[2]) <: Unitful.Unit{:Joule,<:Any}\n    @test typeof(ordered[3]) <: Unitful.Unit{:Kelvin,<:Any}\nend\n\n# Test that the @u_str macro will find units in other modules.\nmodule ShadowUnits\n    using Unitful\n    @unit m \"m\" MyMeter 1u\"m\" false\n    Unitful.register(ShadowUnits)\nend\n\n@test (@test_logs (:warn, r\"found in multiple\") eval(:(typeof(u\"m\")))) ==\n    Unitful.FreeUnits{(Unitful.Unit{:MyMeter, 𝐋}(0, 1//1),), 𝐋, nothing}\n\n# Test that the @u_str macro will not find units in modules which are\n# not loaded before the u_str invocation.\nmodule FooUnits\n    using Unitful\n    @unit foo \"foo\" MyFoo 1u\"m\" false\n    Unitful.register(FooUnits)\nend\n# NB: The following is LoadError in 1.0 but an ErrorException in 0.7.\n@test_throws Exception eval(:(module ShouldUseFooUnits\n                                  using Unitful\n                                  foo() = 1u\"foo\"\n                              end))\n# Test that u_str works when FooUnits is correctly loaded.\nmodule DoesUseFooUnits\n    using Unitful, ..FooUnits\n    foo() = 1u\"foo\"\nend\n@test DoesUseFooUnits.foo() === 1u\"foo\"\n\n# Tests for unit extension modules in unit parsing\n@test_throws ArgumentError uparse(\"foo\", unit_context=Unitful)\n@test uparse(\"foo\", unit_context=FooUnits) === u\"foo\"\n@test uparse(\"foo\", unit_context=[Unitful, FooUnits]) === u\"foo\"\n@test uparse(\"foo\", unit_context=[FooUnits, Unitful]) === u\"foo\"\n\n# Test for #272\nmodule OnlyUstrImported\n    import Unitful: @u_str\n    u = u\"m\"\nend\n@test OnlyUstrImported.u === m\n\n# Test to make sure user macros are working properly\nmodule TUM\n    using Unitful\n    using Test\n\n    @dimension f \"f\" FakeDim12345\n    @derived_dimension FakeDim212345 f^2\n    @refunit fu \"fu\" FakeUnit12345 f false\n    @unit fu2 \"fu2\" FakeUnit212345 1fu false\nend\n\n@testset \"User macros\" begin\n    @test typeof(TUM.f) == Unitful.Dimensions{(Unitful.Dimension{:FakeDim12345}(1//1),)}\n    @test 1(TUM.fu) == 1(TUM.fu2)\n    @test isa(1(TUM.fu), TUM.FakeDim12345)\n    @test isa(TUM.fu, TUM.FakeDim12345Units)\n    @test isa(1(TUM.fu)^2, TUM.FakeDim212345)\n    @test isa(TUM.fu^2, TUM.FakeDim212345Units)\nend\n\nif isdefined(Base, :get_extension)\n    @testset \"ForwardDiff extension, solving Issue 682\" begin\n        @test ForwardDiff.Dual(1.0)*u\"cm/m\" + ForwardDiff.Dual(1.0) == 1.01\n        @test ForwardDiff.Dual(1.0)*u\"cm/m\" == ForwardDiff.Dual(0.01)\n    end\n\n    @testset \"NaNMath extension\" begin\n        @test isnan(NaNMath.sqrt(-1m))\n        @test unit(NaNMath.sqrt(-1m)) == m^(1//2)\n        @test isnan(NaNMath.pow(-1m, 0.5))\n        @test unit(NaNMath.pow(-1m, 0.5)) == m^(1//2)\n        @test NaNMath.sqrt(m) === Base.sqrt(m)\n        @test NaNMath.pow(m, 2) === m^2\n    end\nend\n\nstruct Num <: Real\n   x::Float64\nend\nBase.:+(a::Num, b::Num) = Num(a.x + b.x)\nBase.:-(a::Num, b::Num) = Num(a.x - b.x)\nBase.:*(a::Num, b::Num) = Num(a.x * b.x)\nBase.promote_rule(::Type{Num}, ::Type{<:Real}) = Num\nBase.ArithmeticStyle(::Type{Num}) = Base.ArithmeticRounds()\nBase.OrderStyle(::Type{Num}) = Base.Unordered()\n\n@testset \"Custom types\" begin\n    # Test that @generated functions work with Quantities + custom types (#231)\n    @test uconvert(u\"°C\", Num(373.15)u\"K\") == Num(100)u\"°C\"\nend\n\n@testset \"Traits\" begin\n    @testset \"> ArithmeticStyle\" begin\n        @test Base.ArithmeticStyle(1m) === Base.ArithmeticWraps()\n        @test Base.ArithmeticStyle(1.0m) === Base.ArithmeticRounds()\n        @test Base.ArithmeticStyle((1//1)m) === Base.ArithmeticUnknown()\n        @test Base.ArithmeticStyle(Num(1)m) === Base.ArithmeticRounds()\n    end\n\n    @testset \"> OrderStyle\" begin\n        @test Base.OrderStyle(1m) === Base.Ordered()\n        @test Base.OrderStyle((1+1im)m) === Base.Unordered()\n        @test Base.OrderStyle(Num(1)m) === Base.Unordered()\n    end\nend\n\n@testset \"Encoding\" begin\n    # Julia treats µ (U+00B5) and μ (U+03BC) as the same\n    @test Unitful.µ0 === Unitful.μ0\n    @test Unitful.µm === Unitful.μm\n    @test Unitful.dBµV === Unitful.dBμV\n    @test u\"µ0\" === u\"μ0\"\n    @test u\"µm\" === u\"μm\"\n    @test u\"dBµV\" === u\"dBμV\"\n    @test uparse(\"µ0\") === uparse(\"μ0\")\n    @test uparse(\"µm\") === uparse(\"μm\")\n    @test uparse(\"dBµV\") === uparse(\"dBμV\")\n    @test @doc(Unitful.µm) == @doc(Unitful.μm)\n    # Julia treats ɛ (U+025B) and ε (U+03B5) as the same\n    @test Unitful.ɛ0 === Unitful.ε0\n    @test u\"ɛ0\" === u\"ε0\"\n    @test uparse(\"ɛ0\") === uparse(\"ε0\")\n    @test @doc(Unitful.ɛ0) == @doc(Unitful.ε0)\n    # Julia treats Å (U+00C5) and Å (U+212B) as the same\n    @test Unitful.Å === Unitful.Å\n    @test u\"Å\" === u\"Å\"\n    @test uparse(\"Å\") === uparse(\"Å\")\n    @test @doc(Unitful.Å) == @doc(Unitful.Å)\nend\n\n@testset \"Units aliases\" begin\n    @test Unitful.L === Unitful.l\n    @test Unitful.mL === Unitful.ml\n    @test 1Unitful.L === 1Unitful.l\n    @test 2Unitful.mL === 2Unitful.ml\n    @test Unitful.ϵ0 === Unitful.ε0\n    @test (1//2)Unitful.ϵ0 === (1//2)Unitful.ε0\n    @test Unitful.Å === Unitful.angstrom\n    @test 1.0Unitful.Å === 1.0Unitful.angstrom\n    @test Unitful.deg === Unitful.°\n    @test 2Unitful.° === 2Unitful.deg\n    @test u\"deg\" === u\"°\"\n    @test uparse(\"deg\") === uparse(\"°\")\n    @test Unitful.degC === Unitful.°C\n    @test 2Unitful.°C === 2Unitful.degC\n    @test u\"degC\" === u\"°C\"\n    @test Unitful.degF === Unitful.°F\n    @test 2Unitful.°F === 2Unitful.degF\n    @test u\"degF\" === u\"°F\"\nend\n\nmodule DocUnits\n    using Unitful\n    using Unitful: 𝐋\n    \"dimension docs\"\n    @dimension 𝐃 \"𝐃\" DocDimension true\n    @derived_dimension DerivedDocDimension 𝐃*𝐋 true\n    \"refunit docs\"\n    @refunit dRefFoo \"dRefFoo\" DRefFoo 𝐃 true true\n    \"unit docs\"\n    @unit dFoo \"dFoo\" DFoo 1*dRefFoo*u\"m\" true true\nend\n\nusing REPL # This is necessary to make `@doc` work correctly\n\n@testset \"Docs\" begin\n    @test string(@doc(Unitful.L)) == string(@doc(Unitful.l))\n    @test string(@doc(Unitful.cL)) == string(@doc(Unitful.cl))\n    @test string(@doc(Unitful.ϵ0)) == string(@doc(Unitful.ε0))\n    @test string(@doc(Unitful.Å)) == string(@doc(Unitful.angstrom))\n    @test string(@doc DocUnits.𝐃) == \"dimension docs\\n\"\n    @test string(@doc DocUnits.dRefFoo) == \"refunit docs\\n\"\n    @test string(@doc DocUnits.dFoo) == \"unit docs\\n\"\n    CODEBLOCK_LANG = VERSION ≥ v\"1.12.0-DEV\" ? \"julia\" : \"\"\n    @test string(@doc DocUnits.DocDimension) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.DocDimension{T, U}\n        ```\n\n        A supertype for quantities and levels of dimension [`$(@__MODULE__).DocUnits.𝐃`](@ref) with a value of type `T` and units `U`.\n\n        See also: [`$(@__MODULE__).DocUnits.𝐃`](@ref), `Unitful.Quantity`, `Unitful.Level`.\n        \"\"\"\n    @test string(@doc DocUnits.DocDimensionUnits) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.DocDimensionUnits{U}\n        ```\n\n        A supertype for units of dimension [`$(@__MODULE__).DocUnits.𝐃`](@ref). Equivalent to `Unitful.Units{U, $(@__MODULE__).DocUnits.𝐃}`.\n\n        See also: [`$(@__MODULE__).DocUnits.𝐃`](@ref), `Unitful.Units`.\n        \"\"\"\n    @test string(@doc DocUnits.DocDimensionFreeUnits) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.DocDimensionFreeUnits{U}\n        ```\n\n        A supertype for `Unitful.FreeUnits` of dimension [`$(@__MODULE__).DocUnits.𝐃`](@ref). Equivalent to `Unitful.FreeUnits{U, $(@__MODULE__).DocUnits.𝐃}`.\n\n        See also: [`$(@__MODULE__).DocUnits.𝐃`](@ref).\n        \"\"\"\n    @test string(@doc DocUnits.DerivedDocDimension) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.DerivedDocDimension{T, U}\n        ```\n\n        A supertype for quantities and levels of dimension `𝐃 * 𝐋` with a value of type `T` and units `U`.\n\n        See also: `Unitful.Quantity`, `Unitful.Level`.\n        \"\"\"\n    @test string(@doc DocUnits.DerivedDocDimensionUnits) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.DerivedDocDimensionUnits{U}\n        ```\n\n        A supertype for units of dimension `𝐃 * 𝐋`. Equivalent to `Unitful.Units{U, 𝐃 * 𝐋}`.\n\n        See also: `Unitful.Units`.\n        \"\"\"\n    @test string(@doc DocUnits.DerivedDocDimensionFreeUnits) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.DerivedDocDimensionFreeUnits{U}\n        ```\n\n        A supertype for `Unitful.FreeUnits` of dimension `𝐃 * 𝐋`. Equivalent to `Unitful.FreeUnits{U, 𝐃 * 𝐋}`.\n        \"\"\"\n    @test string(@doc DocUnits.kdFoo) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.kdFoo\n        ```\n\n        A prefixed unit, equal to 10^3 dFoo.\n\n        Dimension: 𝐃 𝐋\n\n        See also: [`$(@__MODULE__).DocUnits.dFoo`](@ref).\n        \"\"\"\n    @test string(@doc DocUnits.kdRefFoo) == \"\"\"\n        ```$CODEBLOCK_LANG\n        $(@__MODULE__).DocUnits.kdRefFoo\n        ```\n\n        A prefixed unit, equal to 10^3 dRefFoo.\n\n        Dimension: 𝐃\n\n        See also: [`$(@__MODULE__).DocUnits.dRefFoo`](@ref).\n        \"\"\"\nend\n\n# Test precompiled Unitful extension modules\nmktempdir() do load_path\n    mktempdir() do load_cache_path\n        write(joinpath(load_path, \"ExampleExtension.jl\"),\n              \"\"\"\n              module ExampleExtension\n              using Unitful\n\n              @unit year \"year\" JulianYear 365u\"d\" true\n\n              function __init__()\n                  Unitful.register(ExampleExtension)\n              end\n              end\n              \"\"\")\n        pushfirst!(LOAD_PATH, load_path)\n        pushfirst!(DEPOT_PATH, load_cache_path)\n        @eval using ExampleExtension\n        # Delay u\"year\" expansion until test time\n        @eval @test uconvert(u\"d\", 1u\"year\") == 365u\"d\"\n    end\nend\n\nusing Aqua\n\nAqua.test_all(Unitful, ambiguities=VERSION≥v\"1.1\", unbound_args=false, piracies=VERSION≥v\"1.8\")\n"
  }
]