Full Code of ajkeller34/Unitful.jl for AI

master 4098e0526252 cached
52 files
490.5 KB
162.7k tokens
1 requests
Download .txt
Showing preview only (514K chars total). Download the full file or copy to clipboard to get everything.
Repository: ajkeller34/Unitful.jl
Branch: master
Commit: 4098e0526252
Files: 52
Total size: 490.5 KB

Directory structure:
gitextract_2l21c_cz/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── CompatHelper.yml
│       ├── TagBot.yml
│       ├── ci.yml
│       └── documentation.yaml
├── .gitignore
├── LICENSE.md
├── NEWS.md
├── Project.toml
├── README.md
├── docs/
│   ├── Project.toml
│   ├── generate_latex_images.jl
│   ├── make.jl
│   └── src/
│       ├── LICENSE.md
│       ├── conversion.md
│       ├── dates.md
│       ├── defaultunits.md
│       ├── display.md
│       ├── extending.md
│       ├── highlights.md
│       ├── index.md
│       ├── latexify.md
│       ├── logarithm.md
│       ├── manipulations.md
│       ├── newunits.md
│       ├── temperature.md
│       ├── trouble.md
│       └── types.md
├── ext/
│   ├── ConstructionBaseUnitfulExt.jl
│   ├── ForwardDiffExt.jl
│   ├── InverseFunctionsUnitfulExt.jl
│   ├── LatexifyExt.jl
│   ├── NaNMathExt.jl
│   └── PrintfExt.jl
├── src/
│   ├── Unitful.jl
│   ├── complex.jl
│   ├── conversion.jl
│   ├── dates.jl
│   ├── dimensions.jl
│   ├── display.jl
│   ├── fastmath.jl
│   ├── logarithm.jl
│   ├── pkgdefaults.jl
│   ├── promotion.jl
│   ├── quantities.jl
│   ├── range.jl
│   ├── types.jl
│   ├── units.jl
│   ├── user.jl
│   └── utils.jl
└── test/
    ├── dates.jl
    └── runtests.jl

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/" # Location of package manifests
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/CompatHelper.yml
================================================
name: CompatHelper
on:
  schedule:
    - cron: 8 14 * * *
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Pkg.add("CompatHelper")
        run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
      - name: CompatHelper.main()
        run: julia -e 'using CompatHelper; CompatHelper.main()'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }}


================================================
FILE: .github/workflows/TagBot.yml
================================================
name: TagBot
on:
  issue_comment:
    types:
      - created
  workflow_dispatch:
jobs:
  TagBot:
    if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
    runs-on: ubuntu-latest
    steps:
      - uses: JuliaRegistries/TagBot@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          ssh: ${{ secrets.DOCUMENTER_KEY }}


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  push:
    branches: "master"
    tags: ["*"]
    paths:
      - '.github/workflows/ci.yml'
      - 'src/**'
      - 'test/**'
      - 'Project.toml'
  pull_request:
    paths:
      - '.github/workflows/ci.yml'
      - 'src/**'
      - 'test/**'
      - 'Project.toml'
  release:

concurrency:
  # Skip intermediate builds: always.
  # Cancel intermediate builds: only if it is a pull request build.
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}

jobs:
  test:
    name: Julia ${{ matrix.julia-version }} - ${{ matrix.os }} - ${{ matrix.julia-arch }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        julia-version:
          - "min"
          - "lts"
          - "1"
          - "pre"
        os:
          - ubuntu-latest
          - macos-latest
          - windows-latest
        julia-arch:
          - "default"
        # Until minimum supported version is v1.6, we can't test on Apple
        # Silicon macOS for that version and we need to use Julia v1.8 instead
        exclude:
          - julia-version: "min"
            os: macos-latest
        include:
          - julia-version: "1.8"
            os: macos-latest
            julia-arch: "default"
    steps:
      - uses: actions/checkout@v6
      - uses: julia-actions/setup-julia@v3
        with:
          version: ${{ matrix.julia-version }}
          arch: ${{ matrix.julia-arch }}
      - uses: julia-actions/cache@v3
      - uses: julia-actions/julia-buildpkg@v1
      - uses: julia-actions/julia-runtest@v1
      - uses: julia-actions/julia-processcoverage@v1
      - uses: codecov/codecov-action@v6
        with:
          files: lcov.info
          fail_ci_if_error: false
      - uses: coverallsapp/github-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          path-to-lcov: lcov.info
          flag-name: run-${{ join(matrix.*, '-') }}
          parallel: true


================================================
FILE: .github/workflows/documentation.yaml
================================================
name: Documentation

on:
  push:
    branches: "master"
    tags: ["*"]
    paths:
      - '.github/workflows/documentation.yaml'
      - 'src/**'
      - 'docs/**'
      - 'Project.toml'
  pull_request:
    paths:
      - '.github/workflows/documentation.yaml'
      - 'src/**'
      - 'docs/**'
      - 'Project.toml'
  release:

concurrency:
  # Skip intermediate builds: always.
  # Cancel intermediate builds: only if it is a pull request build.
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}

jobs:
  Documentation:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: julia-actions/setup-julia@v3
        with:
          version: 1
      - uses: julia-actions/cache@v3
      - uses: julia-actions/julia-docdeploy@v1
        env:
          DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
      - uses: actions/upload-artifact@v7
        with:
          name: documentation-build
          path: docs/build
          retention-days: 90


================================================
FILE: .gitignore
================================================
# Files generated by invoking Julia with --code-coverage
*.jl.cov
*.jl.*.cov

# Files generated by invoking Julia with --track-allocation
*.jl.mem

# Build artifacts for creating documentation generated by the Documenter package
docs/build/
docs/site/

# File generated by Pkg, the package manager, based on a corresponding Project.toml
# It records a fixed state of all packages used by the project. As such, it should not be
# committed for packages, but should be committed for applications that require a static
# environment.
Manifest.toml

*~


================================================
FILE: LICENSE.md
================================================
The Unitful.jl package is licensed under the MIT "Expat" License:

> Copyright (c) 2016: California Institute of Technology and
> [other contributors](https://github.com/JuliaPhysics/Unitful.jl/graphs/contributors).
>
> Permission is hereby granted, free of charge, to any person obtaining
> a copy of this software and associated documentation files (the
> "Software"), to deal in the Software without restriction, including
> without limitation the rights to use, copy, modify, merge, publish,
> distribute, sublicense, and/or sell copies of the Software, and to
> permit persons to whom the Software is furnished to do so, subject to
> the following conditions:
>
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Portions borrow from [EngUnits.jl](https://github.com/dhoegh/EngUnits.jl/blob/master/LICENSE.md),
which is (c) 2016: Daniel Høegh. Unitful.jl's fastmath implementation and tests
draw heavily on those found in [Julia](https://github.com/JuliaLang/julia/blob/master/LICENSE.md).

Neither 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.

Andrew 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).


================================================
FILE: NEWS.md
================================================
# Unitful.jl changelog

## v1.28.0 (2026-01-29)

* ![Feature:](https://img.shields.io/badge/-feature-green) Dimensionless quantities now support `iseven` and `isodd` ([#829](https://github.com/JuliaPhysics/Unitful.jl/pull/829)).
* ![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).

## v1.27.0 (2025-12-08)

* ![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)).

## v1.26.0 (2025-12-05)

* ![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)).
* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Correct LaTeX printing of affine units ([#825](https://github.com/JuliaPhysics/Unitful.jl/pull/825)).
* ![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)).

## v1.25.1 (2025-10-18)

* ![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)).

## v1.25.0 (2025-09-16)

* ![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)).
* This package now requires Julia ≥ 1.6.

## v1.24.0 (2025-07-31)

* ![Feature:](https://img.shields.io/badge/-feature-green) The alias `deg` for `°` is added ([#764](https://github.com/JuliaPhysics/Unitful.jl/pull/764)).

## v1.23.1 (2025-06-10)

* ![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)).

## v1.23.0 (2025-06-08)

* ![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)).
* ![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)).
* ![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)).
* ![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)).

## v1.22.1 (2025-05-13)

* ![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.

## v1.22.0 (2025-01-02)

* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![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)).

## v1.21.1 (2024-11-29)

* ![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)).
* ![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)).
* ![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)).
* The documentation now contains a list of all units and constants defined in this package ([#729](https://github.com/JuliaPhysics/Unitful.jl/pull/729)).

## v1.21.0 (2024-07-19)

* ![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)).

## v1.20.0 (2024-05-17)

* ![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)).
* ![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)).
* ![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),
  norm(y))` ([#719](https://github.com/JuliaPhysics/Unitful.jl/pull/719)).

## v1.19.1 (2024-05-13)

* ![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)).
* ![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)).

## v1.19.0 (2023-11-29)

* ![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)).

## v1.18.0 (2023-11-13)

* ![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)).

## v1.17.0 (2023-08-24)

* ![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)).

## v1.16.3 (2023-08-14)

* ![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)).
* ![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)).
* ![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)).

## v1.16.2 (2023-08-05)

* ![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)).

## v1.16.1 (2023-08-02)

* ![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)).

## v1.16.0 (2023-08-01)

* ![Feature:](https://img.shields.io/badge/-feature-green) The derived dimension `MolarMass` (`𝐌/𝐍`) is added ([#663](https://github.com/JuliaPhysics/Unitful.jl/pull/663)).
* ![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)).

## v1.15.0 (2023-07-05)

* ![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)).
* ![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)).

## v1.14.0 (2023-05-11)

* ![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)).
* ![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)).

## v1.13.1 (2023-04-15)

* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Adapt test suite for Julia 1.9 ([#643](https://github.com/JuliaPhysics/Unitful.jl/pull/643)).

## v1.13.0 (2023-04-11)

* ![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)).
* ![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)).
* ![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)).
* 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)).

## v1.12.4 (2023-02-27)

* ![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)).

## v1.12.3 (2023-02-10)

* ![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)).
* ![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)).

## v1.12.2 (2022-11-30)

* ![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)).

## v1.12.1 (2022-11-18)

* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Fixed `istriu`/`istril` for affine quantities ([#572](https://github.com/JuliaPhysics/Unitful.jl/pull/572)).

## v1.12.0 (2022-09-17)

* ![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)).
* ![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)).
* ![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)).

## v1.11.0 (2022-02-10)

* ![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)).
* ![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)).
* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) Method ambiguities of `Base._range` are resolved ([#514](https://github.com/JuliaPhysics/Unitful.jl/pull/514)).
* ![Maintenance:](https://img.shields.io/badge/-maintenance-grey) Updated `range` implementation for Julia ≥ 1.8 ([#514](https://github.com/JuliaPhysics/Unitful.jl/pull/514)).

## v1.10.1 (2022-01-03)

* ![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)).

## v1.10.0 (2021-12-27)

* ![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)).
* ![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)).
* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Fixed some invalidations to improve compile times ([#509](https://github.com/JuliaPhysics/Unitful.jl/pull/509)).
* ![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)).
* ![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)).

## v1.9.2 (2021-11-12)

* ![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)).

## v1.9.1 (2021-10-27)

* ![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)).
* ![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)).
* ![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)).

## v1.9.0 (2021-07-16)

* ![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)).

## v1.8.0 (2021-05-31)

* ![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)).

## v1.7.0 (2021-04-02)

* ![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)).
* ![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)).

## v1.6.0 (2021-02-14)

* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Macro hygiene is improved ([#390](https://github.com/JuliaPhysics/Unitful.jl/pull/390)).

## v1.5.0 (2020-10-21)

* ![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)).

## v1.4.1 (2020-09-17)

* ![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)).

## v1.4.0 (2020-08-11)

* ![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)).
* ![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)).

## v1.3.0 (2020-06-26)

* ![Feature:](https://img.shields.io/badge/-feature-green) `isless` is now defined for logarithmic quantities ([#315](https://github.com/JuliaPhysics/Unitful.jl/pull/315)).
* ![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)).
* ![Enhancement:](https://img.shields.io/badge/-enhancement-blue) Custom printing of types was removed ([#322](https://github.com/JuliaPhysics/Unitful.jl/pull/322)).

## v1.2.1 (2020-05-26)

* ![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)).

## v1.2.0 (2020-05-10)

* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Year` now allows SI prefixes ([#320](https://github.com/JuliaPhysics/Unitful.jl/pull/320)).
* ![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)).

## v1.1.0 (2020-04-09)

* ![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)).
* ![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)).
* ![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)).
* ![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)).

## v1.0.0 (2020-01-27)

* ![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)).
* ![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)).
* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Pertenthousand` (`‱`) is added ([#294](https://github.com/JuliaPhysics/Unitful.jl/pull/294)).
* ![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)).

## v0.18.0 (2019-11-27)

* ![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)).
* ![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)).
* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Angstrom` (`Å` or `angstrom`) is added ([#271](https://github.com/JuliaPhysics/Unitful.jl/pull/271)).

## v0.17.0 (2019-09-08)

* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![Feature:](https://img.shields.io/badge/-feature-green) The unit `Molar` (`M`) is added ([#258](https://github.com/JuliaPhysics/Unitful.jl/pull/258)).
* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![Bugfix:](https://img.shields.io/badge/-bugfix-purple) `Unitful.promote_to_derived` works again ([#252](https://github.com/JuliaPhysics/Unitful.jl/pull/252)).

## v0.16.0 (2019-07-01)

* ![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)).
* ![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)).
* ![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)).
* ![Feature:](https://img.shields.io/badge/-feature-green) The function `upreferred` now supports `missing` ([#224](https://github.com/JuliaPhysics/Unitful.jl/pull/224)).
* ![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)).
* ![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)).
* ![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)).
* ![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)).

## v0.15.0 (2019-03-05)

* ![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)).
* ![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)).
* ![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)).
* ![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)).
* ![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)).

## Older changes

- v0.14.0
  - Support for `digits` kwarg (#196).
  - Try to support precompilation with `u_str` macro (#201).
- v0.13.0
  - Implement affine quantities for better temperature handling (#177, #182).
  - Rename `°Ra` to `Ra` to emphasize that it is an absolute scale.
  - Fix some precompilation issues (#161).
  - Add `Velocity`, `Acceleration`, `Density` derived dimensions (#187).
  - Days display as `d` now (#184).
  - Type signature of `Quantity`s has been simplified. Helps with reading error messages (#183).
  - Support `isequal` with `NaN` quantities (#172).
- v0.12.0
  - Bug fixes.
  - Support carrier-to-noise-density ratio (C/N0) in dB-Hz.
  - Added dimensions: `DField`, `EField`, `ElectricDipoleMoment`, `ElectricQuadrupoleMoment`, `MagneticDipoleMoment`.
  - Added unit: `barn`.
  - Some documentation improvements.
- v0.11.0--v0.9.0
  - Fixes for Julia 0.7 update, primarily.
  - Some new TwicePrecision functionality for quantities.
- v0.8.0
  - Add Rydberg constant, unified atomic mass unit, mils, rpm, rps, percent, permille.
  - Introduce/rename derived dimensions: ElectricalConductivity, ElectricalResistivity,
    ElectricalConductance, ElectricalResistance.
  - Fix some Julia 0.7 deprecations.
  - This will probably be the last release that supports Julia 0.6.
- v0.7.1
  - Bug fixes, mainly.
- v0.7.0
  - Implement `mod2pi` for degrees, cleanup display of degree units.
  - Tweak implementation of `Gain` types for usability.
  - Implement `zero` and `one` for `Level` and `Gain`.
  - Add a few more cgs units.
  - Tests pass on 32-bit systems, for the first time in a long time (ever?).
- v0.6.1
  - Permit symbols that are bound to `Number`s to be used in `u_str` macro, such that
    π and other non-literal numbers can be used.
  - Add some cgs units and a few dimensions [#115](https://github.com/JuliaPhysics/Unitful.jl/pull/115).
  - Fix a comparison / promotion bug introduced in v0.6.0.
- v0.6.0
  - Restore compatibility with 0.7.0-DEV.
- v0.5.1
  - Dimensionless quantities no longer lose their units when dividing by a real number.
  - Ranges constructed via `range` or `colon` should work more reliably (e.g., 0:10°:350° works now).
- v0.5.0
  - Add `dBΩ` and `dBS` to permit working with impedances and admittances in dB. These are
    used in the Touchstone format and in microwave measurements.
  - Implement `angle` for `Quantity{<:Complex}`.
  - Implement `float` for `Gain`, `Level`.
  - Replace `fieldratio` and `rootpowerratio` with `uconvertrp`.
    - Permits unit conversion between `NoUnits` and `dB`, etc. by presuming unitless ratios
      are of root-power quantities (hence the `rp` after `uconvert`).
    - `uconvertrp` has generic fallbacks and can be used as a drop-in replacement for
      `uconvert` otherwise.
  - Likewise, replace `powerratio` with `uconvertp` for ratios of power quantities.
  - Introduce `convertrp` and `convertp`. These are like `convert` but they make
    similar assumptions about unitless ratios being of power or root-power quantities,
    respectively.
  - Implement more division operations for `Gain`s (accidental omissions)
- v0.4.0
  - Introduce logarithmic quantities (experimental!)
  - Update syntax for Julia 0.6 and reorganize code for clarity.
  - Redefine `ustrip(x::Quantity) = ustrip(x.val)`. In most cases, this is unlikely to
    affect user code. The generic fallback `ustrip(x::Number)` remains unchanged.
  - `isapprox(1.0u"m",5)` returns `false` instead of throwing a `DimensionError`,
    in keeping with the behavior of an equality check (`==`).
  - Display of some units has changed to match their symbols [#104](https://github.com/JuliaPhysics/Unitful.jl/issues/104).
  - Don't export `cd` from Unitful.DefaultSymbols in order to avoid conflicts [#102](https://github.com/JuliaPhysics/Unitful.jl/issues/102).
  - Deprecated `dimension(x::AbstractArray{T}) where T<:Number`, use broadcasting instead.
  - Deprecated `dimension(x::AbstractArray{T}) where T<:Units`, use broadcasting instead.
  - Deprecated `ustrip(A::AbstractArray{T}) where T<:Number`, use broadcasting instead.
  - Deprecated `ustrip(A::AbstractArray{T}) where T<:Quantity`, use broadcasting instead.
- v0.3.0
  - Require Julia 0.6
  - Adds overloads for `rand` and `ones` [#96](https://github.com/JuliaPhysics/Unitful.jl/issues/96).
  - Improve symbol resolution in `u_str` macro [#98](https://github.com/JuliaPhysics/Unitful.jl/pull/98).
  - More work is done inside the `u_str` macro, such that the macro returns units, dimensions,
    numbers (quantities), or tuples rather than expressions.
- v0.2.6
  - Fix and close [#52](https://github.com/JuliaPhysics/Unitful.jl/issues/52).
  - Implement `Base.rtoldefault` for Quantity types
    (needed for AxisArrays [#52](https://github.com/JuliaArrays/AxisArrays.jl/pull/52)).
- v0.2.5
  - Fix and close [#79](https://github.com/JuliaPhysics/Unitful.jl/issues/79).
  - Add support for `round(T, ::DimensionlessQuantity)` where `T <: Integer`
    (also `floor`, `ceil`, `trunc`) [#90](https://github.com/JuliaPhysics/Unitful.jl/pull/90).
- v0.2.4
  - Bug fix: avoid four-argument `promote_type`
  - Bug fix: define method for `*(::Base.TwicePrecision, ::Quantity)`
  - Bug fix: definition of Bohr magneton had `e` instead of `q`
- v0.2.3
  - Dimensionful quantities are no longer accepted for `floor`, `ceil`, `trunc`, `round`,
    `isinteger`. The choice of units can yield physically different results.
    The functions are defined for dimensionless quantities, and return unitless numbers.
    Closes [#78](https://github.com/JuliaPhysics/Unitful.jl/issues/78).
  - Added `gn`, a constant quantity for the gravitational acceleration on earth
    [#75](https://github.com/JuliaPhysics/Unitful.jl/pull/75).
  - Added `ge`, the gravitational acceleration on earth as a unit
    [#75](https://github.com/JuliaPhysics/Unitful.jl/pull/75).
  - Added `lbf`, pounds-force unit
    [#75](https://github.com/JuliaPhysics/Unitful.jl/pull/75).
- v0.2.2
  - Fixed a bug in promotion involving `ContextUnits` where the promotion context might
    not be properly retained.
- v0.2.1
  - Fixed `isapprox` bug [#74](https://github.com/JuliaPhysics/Unitful.jl/pull/74).
  - Added `DimensionlessQuantity` methods for `exp`, `exp10`, `exp2`, `expm1`, `log1p`,
    `log2` [#71](https://github.com/JuliaPhysics/Unitful.jl/pull/71).
- v0.2.0
  - `Units{N,D}` is now an abstract type. Different concrete types for units give different
   behavior under conversion and promotion. The currently implemented concrete types are:
    - `FreeUnits{N,D}`: these give the typical behavior from prior versions of Unitful.
      Units defined in Unitful.jl and reachable by the `u_str` macro are all `FreeUnits`.
    - `ContextUnits{N,D,P}`, where P is some type `FreeUnits{M,D}`: these enable
      context-specific promotion rules, e.g. if units are defined in different packages.
    - `FixedUnits{N,D}`: these inhibit automatic conversion of quantities with different units.
  - `LengthUnit`, `EnergyUnit`, etc. are renamed to `LengthUnits`, `EnergyUnits`, etc. for
    consistency (they are related more to `Units` objects than `Unit` objects). You can
    still use the old names for now, but please switch over to using `...Units` instead
    of `...Unit` in this release as the old names will be removed in a future release.
  - `c` is now a unit, to permit converting mass into `MeV/c^2`, for example. `c0` is
    still a quantity equal to the speed of light in vacuum, in units of `m/s`
    [#67](https://github.com/JuliaPhysics/Unitful.jl/issues/67).
- v0.1.5
  - Patch for Julia PR [#20889](https://github.com/JuliaLang/julia/pull/20889), which
    changes how lowering is done for exponentiation of integer literals.
  - Bug fix to enable registering Main as a module for `u_str` (fixes
    [#61](https://github.com/JuliaPhysics/Unitful.jl/issues/61)).
  - Implement readable message for `DimensionError`
    [#62](https://github.com/JuliaPhysics/Unitful.jl/pull/62).
- v0.1.4
  - Critical bug fix owing to `mod_fast` changes.
- v0.1.3
  - Fix symmetry of `==` [#56](https://github.com/JuliaPhysics/Unitful.jl/issues/56).
  - Using `@refunit` will implicitly specify the ref. unit as the default for promotion.
    This will not change behavior for most people; it just ensures promotion won't
    fail for quantities with user-defined dimensions.
  - Remove `mod_fast` in anticipation of Julia PR [#20859](https://github.com/JuliaLang/julia/pull/20859).
  - Allow tolerance args for `isapprox` [#57](https://github.com/JuliaPhysics/Unitful.jl/pull/57)
- v0.1.2
  - On Julia 0.6, exponentiation by a literal is now type stable for integers.
- v0.1.1
  - Fixed a macro hygiene issue that prevented `@dimension` and `@derived_dimension`
   from working properly if Compat was not imported in the calling namespace.
- v0.1.0
  - Julia 0.6 compatibility.
  - On Julia 0.6, exponentiation by a literal is now type stable for
    common integer powers: -3, -2, -1, 0, 1, 2, 3.
  - Added missing methods for dot operators `.<` and `.<=` (Julia 0.5, fix
    [#55](https://github.com/JuliaPhysics/Unitful.jl/issues/55)).
  - Fix [#45](https://github.com/JuliaPhysics/Unitful.jl/issues/45). Ranges should
    work as expected on Julia 0.6. On Julia 0.5, [Ranges.jl](https://github.com/JuliaArrays/Ranges.jl)
    is used to make ranges work as well as possible given limitations in Base.
  - Fix [#33](https://github.com/JuliaPhysics/Unitful.jl/issues/33),
    [#42](https://github.com/JuliaPhysics/Unitful.jl/issues/42),
    and [#50](https://github.com/JuliaPhysics/Unitful.jl/issues/50).
    `deps/Defaults.jl` is dead. Long live `deps/Defaults.jl`. To define your own
    units, dimensions, and so on, you should now put them in a module, or ideally
    a package so that others can use the definitions too. You can override default
    promotion rules immediately after loading Unitful and dependent packages; this
    will generate method overwrite warnings on Julia 0.5 but not on 0.6.
  - `@u_str` macro has been improved. It can now traverse separate unit packages,
    as well as return tuples of `Units` objects.
  - `@preferunit` has been replaced with a function `preferunits`.
  - Added some methods for `ustrip`.
  - Implement `typemin`, `typemax`, `cbrt` for `Quantity`s.
  - Added matrix inversion for `StridedMatrix{T<:Quantity}`.
  - Added `istriu`, `istril` for `AbstractMatrix{T<:Quantity}`.
  - The `Unitful.SIUnits` module has been renamed to `Unitful.DefaultSymbols`.
  - Add `lb`, `oz`, `dr`, `gr` to Unitful (international Avoirdupois mass units).
- v0.0.4
  - Be aware, breaking changes to `deps/Defaults.jl` caused by some of the following!
  - Fix [#40](https://github.com/JuliaPhysics/Unitful.jl/issues/40).
  - Fix [#30](https://github.com/JuliaPhysics/Unitful.jl/issues/30).
  - Support relevant `@fastmath` operations for `Quantity`s.
  - Implement `fma`, `atan2` for `Quantity`s.
  - Implement `cis` for dimensionless `Quantity`s.
  - Removed `DimensionedUnits` and `DimensionedQuantity` abstract types.
    They were of dubious utility, and this change shortened the promotion code
    considerably. More importantly, this change has made it possible to write
    methods like the following, without method ambiguities:
    `uconvert(e::EnergyUnit, f::Frequency) = uconvert(e, u"h"*f)`.
  - Promotion wraps usual `Number` types in dimensionless, unitless `Quantity`
    types when promoted together with dimensionful `Quantity`s.
    With `Quantity`s it is not always possible to promote to a common
    concrete type, but this way we can at least ensure that the numeric backing
    types are all promoted: (`promote(1.0u"m", 1u"N"//2, 0x08) == (1.0 m,0.5 N,8.0)`,
    where `8.0` is actually a dimensionless, unitless `Quantity`).
    The usual outer constructor for `Quantity`s (`Quantity(val::T, unit)`)
    continues to return a number of type `T` if the unit is `NoUnits`,
    since most of the time the user would prefer a `Number` type from base rather
    than a dimensionless, unitless quantity.
  - Add more units to defaults: `bar` (bar), `Torr` (torr), `atm` (atmosphere),
    `l` or `L` (liter; both symbols accepted). You will need to delete
    `deps/Defaults.jl` in the Unitful package directory to get the new units.
  - Two character encodings for `μ` in SI prefixes are now generated automatically
    (some logic moved out of defaults).
  - Moved definition of `sin`, `cos`, `tan`, `sec`, `csc`, `cot` out of
    `deps/build.jl` and into `src/Unitful.jl`.
- v0.0.3
  - Bug fix: `uconvert(°C, 0x01°C)` no longer disturbs the numeric type
  - Allow μ-prefixed units to be typed with option-m on a Mac, in addition to
    using Unicode. Previously only `μm` could be typed this way.
  - Include a `baremodule` called `SIUnits` in the factory defaults. You can
    now do `using Unitful.SIUnits` to bring all of the SI units into the calling
    namespace.
  - Added remaining SI units to the factory defaults: `sr` (steradian), `lm`
    (luminous flux), `lx` (illuminance), `Bq` (becquerel), `Gy` (gray),
    `Sv` (sievert), `kat` (katal).
  - Simplify array creation, as in `[1, 2]u"km"` [#29](https://github.com/JuliaPhysics/Unitful.jl/pull/29)
  - Support multiplying ranges by units, as in `(1:3)*mm` [#28](https://github.com/JuliaPhysics/Unitful.jl/pull/28)
  - Bug fix [#26](https://github.com/JuliaPhysics/Unitful.jl/issues/26)
  - Promoting `Quantity`s with different dimensions now returns quantities with
    the same numeric backing type, e.g. `Quantity{Float64}`. Ideally, this would
    also be true if you mixed unitless and unitful numbers during promotion, but
    that is not yet the case. See [#24](https://github.com/JuliaPhysics/Unitful.jl/issues/24)
    for motivation.
- v0.0.2
  - Bug fixes (`[1.0m, 2.0m] ./ 3` would throw a `Unitful.DimensionError()`).
    Promotion still isn't perfect, but it is hard for me to see what `@inferred`
    errors are real until https://github.com/JuliaLang/julia/issues/18465 is resolved.
  - Made units callable for unit conversion: `u"cm"(1u"m") == 100u"cm"//1`.
    Note that `Units` objects have no fields, so this is totally unambiguous.
    Moreover, we have convenient syntax for unit conversion by function chaining:
    `1u"m" |> u"cm" == 100u"cm"//1`. Note that `uconvert` will remain supported.
- v0.0.1 - Initial release


================================================
FILE: Project.toml
================================================
name = "Unitful"
uuid = "1986cc42-f94f-5a68-af5c-568840ba703d"
version = "1.28.0"

[deps]
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[weakdeps]
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[extensions]
ConstructionBaseUnitfulExt = "ConstructionBase"
ForwardDiffExt = "ForwardDiff"
InverseFunctionsUnitfulExt = "InverseFunctions"
LatexifyExt = ["Latexify", "LaTeXStrings"]
NaNMathExt = "NaNMath"
PrintfExt = "Printf"

[compat]
Aqua = "0.8"
ConstructionBase = "1"
Dates = "<0.0.1, 1"
ForwardDiff = "0.10, 1"
InverseFunctions = "0.1"
LaTeXStrings = "1.2.0"
Latexify = "0.16.8"
LinearAlgebra = "<0.0.1, 1"
NaNMath = "1"
Printf = "<0.0.1, 1"
REPL = "<0.0.1, 1"
Random = "<0.0.1, 1"
Test = "<0.0.1, 1"
julia = "1.6"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Aqua", "ConstructionBase", "ForwardDiff", "InverseFunctions", "Latexify", "LaTeXStrings", "LinearAlgebra", "NaNMath", "Test", "Random", "REPL", "Printf"]


================================================
FILE: README.md
================================================
[![CI](https://github.com/JuliaPhysics/Unitful.jl/workflows/CI/badge.svg)](https://github.com/JuliaPhysics/Unitful.jl/actions?query=workflow%3ACI)
[![Coverage Status](https://coveralls.io/repos/github/JuliaPhysics/Unitful.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaPhysics/Unitful.jl?branch=master)
[![codecov.io](https://codecov.io/github/JuliaPhysics/Unitful.jl/coverage.svg?branch=master)](https://codecov.io/github/JuliaPhysics/Unitful.jl?branch=master)



# Unitful.jl

Unitful is a Julia package for physical units. We want to support not only
SI units but also any other unit system. We also want to minimize or in some
cases eliminate the run-time penalty of units. There should be facilities
for dimensional analysis. All of this should integrate easily with the usual
mathematical operations and collections that are found in Julia base.

### 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)


## Other packages in the Unitful family

### Units packages

- [UnitfulUS.jl](https://github.com/PainterQubits/UnitfulUS.jl): U.S. customary units. Serves as an example for how to implement a units
  package.
- [UnitfulAstro.jl](https://github.com/mweastwood/UnitfulAstro.jl): Astronomical units.
- [UnitfulAngles.jl](https://github.com/yakir12/UnitfulAngles.jl): More angular units, additional trigonometric functionalities, and clock-angle conversion.
- [UnitfulAtomic.jl](https://github.com/sostock/UnitfulAtomic.jl): Easy conversion from and to atomic units.
- [PowerSystemsUnits.jl](https://github.com/invenia/PowerSystemsUnits.jl): Common units for dealing with power systems.
- [UnitfulMoles.jl](https://github.com/rafaqz/UnitfulMoles.jl) for defining mol units of chemical elements and compounds.

### Feature additions

- [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.
- [UnitfulParsableString.jl](https://github.com/michikawa07/UnitfulParsableString.jl): Add a `Base.string` method that converts quantities and units to parsable strings.
- [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.
- [NaturallyUnitful.jl](https://github.com/MasonProtter/NaturallyUnitful.jl): Convert to and from natural units in physics.
- [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.
- [DimensionfulAngles.jl](https://github.com/JuliaOceanWaves/DimensionfulAngles.jl): Adds angle as a dimension. This allows dispatching on angles and derived quantities.
- [Dimensionless.jl](https://github.com/martinkosch/Dimensionless.jl): Contains tools to switch between dimensional bases, conduct dimensional analysis and solve similitude problems.
- [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.)
- [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.)


## Related packages

Unitful was inspired by:

- [SIUnits.jl](https://github.com/keno/SIUnits.jl)
- [EngUnits.jl](https://github.com/dhoegh/EngUnits.jl)
- [Units.jl](https://github.com/timholy/Units.jl)


================================================
FILE: docs/Project.toml
================================================
[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Fontconfig = "186bb1d3-e1f7-5a2c-a377-96d770f13627"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
tectonic_jll = "d7dd28d6-a5e6-559c-9131-7eb760cdacc5"

[sources]
Unitful = {path = ".."}

[compat]
Documenter = "1"
Latexify = "0.16.10"
Plots = "1"
Fontconfig = "0.4"


================================================
FILE: docs/generate_latex_images.jl
================================================
using LaTeXStrings, Unitful, Latexify
import tectonic_jll # needed for lightweight LaTeX render
using Fontconfig: format, match, Pattern

# Since the docs can get built on different systems, we need to find a locally installed 
# monospaced font that has enough Unicode coverage to handle π
monofont = format(match(Pattern(spacing=100, charset="3c0")), "%{family}")

commands = [
    :(latexify(612.2u"nm")),
    :(latexify(u"kg*m/s^2")),
    :(latexify(612.2u"nm"; fmt=SiunitxNumberFormatter())),
    :(latexify(u"kg*m/s^2"; fmt=SiunitxNumberFormatter())),
    :(latexify(612.2u"nm"; fmt=SiunitxNumberFormatter(; simple=true))),
    :(latexify(u"kg*m/s^2"; fmt=SiunitxNumberFormatter(; simple=true))),
    :(latexify((1, 2, 4) .* u"m"; fmt=SiunitxNumberFormatter())),
]
tab1 = map(commands) do command
    LaTeXString.([
        "\\verb+$(string(command))+",
        "\\verb+$(eval(command))+",
        "$(eval(command)) ",
    ])
end
ltab1 = latextabular(tab1, adjustment=:l, transpose=true, latex=false, booktabs=true, 
    head=["julia", "\\LaTeX", "Result"])
# Setting an explicit white background color results in transparent PDF, so go offwhite.
ltab1 = LaTeXString("""
    \\setmonofont{$monofont}
    \\definecolor{offwhite}{rgb}{0.999,0.999,0.999}
    \\pagecolor{offwhite}
    \\color{black}
""" * ltab1)

render(ltab1, MIME("image/png"); use_tectonic=true, open=false,
    name=(@__DIR__)*"/src/assets/latex-examples", 
    packages=["booktabs", "color", "siunitx", "fontspec"], 
    documentclass=("standalone"))

functions = [
    x -> "\\verb+$(string(x))+",
    x -> latexify(x),
    x -> latexify(x; fmt=SiunitxNumberFormatter()),
    x -> latexify(x; fmt=SiunitxNumberFormatter(; simple=true)),
]
allunits = begin
    uparse.([
        "nH*m/Hz",
        "m",
        "s",
        "A",
        "K",
        "cd",
        "g",
        "mol",
        "sr",
        "rad",
        "°",
        "Hz",
        "N",
        "Pa",
        "J",
        "W",
        "C",
        "V",
        "S",
        "F",
        "H",
        "T",
        "Wb",
        "lm",
        "lx",
        "Bq",
        "Gy",
        "Sv",
        "kat",
        #"percent", # Messes with comments
        # "permille", # Undefined in all formats
        # "pertenthousand", # Undefined in all formats (butchered)
        "°C",
        "°F", # No longer in siunitx
        "minute",
        "hr",
        "d",
        "wk", # Undefined in siunitx
        "yr", # Undefined in siunitx
        "rps", # Undefined in siunitx
        "rpm", # Undefined in siunitx
        "a", # Undefined in siunitx
        "b",
        "L",
        "M", # Undefined in siunitx
        "eV",
        "Hz2π", # Butchered by encoding
        "bar",
        "atm", # Undefined in siunitx
        "Torr", # Undefined in siunitx
        "c", # Undefined in siunitx
        "u", # Undefined in siunitx
        "ge", # Undefined in siunitx
        "Gal", # Undefined in siunitx
        "dyn", # Undefined in siunitx
        "erg", # Undefined in siunitx
        "Ba", # Undefined in siunitx
        "P", # Undefined in siunitx
        "St", # Undefined in siunitx
        #"Gauss", # errors in testing, maybe from Unitful.jl's dev branch?
        #"Oe", # errors in testing, maybe from Unitful.jl's dev branch?
        #"Mx", # errors in testing, maybe from Unitful.jl's dev branch?
        "inch", # Undefined in siunitx
        "mil", # Undefined in siunitx
        "ft", # Undefined in siunitx
        "yd", # Undefined in siunitx
        "mi", # Undefined in siunitx
        "angstrom", # Undefined in mathrm,siunitxsimple
        "ac", # Undefined in siunitx
        "Ra", # Undefined in siunitx
        "lb", # Undefined in siunitx
        "oz", # Undefined in siunitx
        "slug", # Undefined in siunitx
        "dr", # Undefined in siunitx
        "gr", # Undefined in siunitx
        "lbf", # Undefined in siunitx
        "cal", # Undefined in siunitx
        "btu", # Undefined in siunitx
        "psi", # Undefined in siunitx
        #"dBHz", # Cannot *yet* be latexified.
        #"dBm", # Cannot *yet* be latexified.
        #"dBV", # Cannot *yet* be latexified.
        #"dBu", # Cannot *yet* be latexified.
        #"dBμV", # Cannot *yet* be latexified.
        #"dBSPL", # Cannot *yet* be latexified.
        #"dBFS", # Cannot *yet* be latexified.
        #"dBΩ", # Cannot *yet* be latexified.
        #"dBS", # Cannot *yet* be latexified.
    ])
end

tab2 = map(allunits) do unit
    [LaTeXString(f(unit)) for f in functions]
end
ltab2 = latextabular(tab2, adjustment=:l, transpose=true, latex=false, booktabs=true, 
    head=["Name", "Default number formatter", "\\verb+SiunitxNumberFormatter()+", "\\verb+SiunitxNumberFormatter(;simple=true)+"])
# Set background to not-quite-white so it doesn't get treated as transparent
ltab2 = LaTeXString(
    """
    \\setmonofont{$monofont}
    \\definecolor{offwhite}{rgb}{0.999,0.999,0.999}
    \\pagecolor{offwhite}
    \\color{black}
    """ * ltab2)

render(ltab2, MIME("image/png"); use_tectonic=true, open=false,
    tectonic_flags=`-Z continue-on-errors`,
    name=(@__DIR__)*"/src/assets/latex-allunits", 
    packages=["booktabs", "color", "siunitx", "fontspec"], 
    documentclass=("standalone"))


================================================
FILE: docs/make.jl
================================================
using Documenter, Unitful, Dates

@info "Generating latex images for documentation"
include("generate_latex_images.jl")

DocMeta.setdocmeta!(Unitful, :DocTestSetup, :(using Unitful))
withenv("UNITFUL_FANCY_EXPONENTS" => "false") do
    makedocs(
        sitename = "Unitful.jl",
        format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"),
        warnonly = [:missing_docs],
        modules = [Unitful],
        workdir = joinpath(@__DIR__, ".."),
        pages = [
            "Home" => "index.md"
            "Highlighted features" => "highlights.md"
            "Types" => "types.md"
            "Defining new units" => "newunits.md"
            "Conversion/promotion" => "conversion.md"
            "Manipulating units" => "manipulations.md"
            "How units are displayed" => "display.md"
            "Logarithmic scales" => "logarithm.md"
            "Temperature scales" => "temperature.md"
            "Interoperability with `Dates`" => "dates.md"
            "Latexifying units" => "latexify.md"
            "Extending Unitful" => "extending.md"
            "Troubleshooting" => "trouble.md"
            "Pre-defined dimensions, units, and constants" => "defaultunits.md"
            "License" => "LICENSE.md"
        ]
    )
end

deploydocs(repo = "github.com/JuliaPhysics/Unitful.jl.git")


================================================
FILE: docs/src/LICENSE.md
================================================
# License

```@eval
using Markdown
open(Markdown.parse, "LICENSE.md")
```


================================================
FILE: docs/src/conversion.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Conversion/promotion

## Converting between units

Since `convert` in Julia already means something specific (conversion between
Julia types), we define [`uconvert`](@ref) for conversion between units. Typically
this will also involve a conversion between types, but this function takes care
of figuring out which type is appropriate for representing the desired units.

Exact conversions between units are respected where possible. If rational
arithmetic would result in an overflow, then floating-point conversion should
proceed. Use of floating-point numbers inhibits exact conversion.

```@docs
uconvert
```

Since objects are callable, we can also make [`Unitful.Units`](@ref) callable
with a `Number` as an argument, for a unit conversion shorthand:

```jldoctest
julia> u"cm"(1u"m")
100 cm
```

This syntax is a little confusing, but becomes appealing with the function
chaining operator `|>`:

```jldoctest
julia> 1u"m" |> u"cm"
100 cm
```

Note that since [`Unitful.Units`](@ref) objects have no fields, we don't have
to worry about ambiguity with constructor calls. This way of converting units
results in behavior identical to calling [`uconvert`](@ref).

### Dimensionless quantities

For dimensionless quantities, `uconvert` can be used with the [`NoUnits`](@ref) unit to
strip the units without losing power-of-ten information:

```jldoctest
julia> uconvert(NoUnits, 1.0u"μm/m")
1.0e-6

julia> uconvert(NoUnits, 1.0u"m")
ERROR: DimensionError:  and m are not dimensionally compatible.
```

```@docs
Unitful.NoUnits
```

You can also directly convert to a subtype of `Real` or `Complex`:

```jldoctest
julia> convert(Float64, 1.0u"μm/m")
1.0e-6
```

## Basic promotion mechanisms

We decide the result units for addition and subtraction operations based on looking at the
types only. We can't take runtime values into account without compromising runtime
performance.

If two quantities with the same units are added or subtracted, then the result units
will be the same. If two quantities with differing units (but same dimension) are added
or subtracted, then the result units will be specified by promotion.

### Promotion rules for specific dimensions

You can specify the result units for promoting quantities of a specific dimension
once at the start of a Julia session. For example, you can specify that when promoting
two quantities with different energy units, the resulting quantities should be in
`g*cm^2/s^2`. This is accomplished by defining a `Unitful.promote_unit` method for the units
themselves. Here's an example.

```jldoctest
julia> using Unitful

julia> Unitful.promote_unit(::S, ::T) where {S<:Unitful.EnergyUnits, T<:Unitful.EnergyUnits} = u"g*cm^2/s^2"

julia> promote(2.0u"J", 1.0u"kg*m^2/s^2")
(2.0e7 g cm^2 s^-2, 1.0e7 g cm^2 s^-2)

julia> Unitful.promote_unit(::S, ::T) where {S<:Unitful.EnergyUnits, T<:Unitful.EnergyUnits} = u"J"

julia> promote(2.0u"J", 1.0u"kg*m^2/s^2")
(2.0 J, 1.0 J)
```

If you're wondering where `Unitful.EnergyUnits` comes from, it is defined in
`src/pkgdefaults.jl` by the [`@derived_dimension`](@ref) macro. Similarly,
the calls to the [`@dimension`](@ref) macro define `Unitful.LengthUnits`,
`Unitful.MassUnits`, etc. None of these are exported.

Existing users of Unitful may want to call [`Unitful.promote_to_derived`](@ref)
after Unitful loads to give similar behavior to Unitful 0.0.4 and below. It is
not called by default.

```@docs
Unitful.promote_to_derived
```

### Fallback promotion rules

The [`Unitful.preferunits`](@ref) function is used to designate fallback
preferred units for each pure dimension for promotion. Such a fallback is
required because you need some generic logic to take over when manipulating
quantities with arbitrary dimensions.

The default behavior is to promote to a combination of the base SI units, i.e.
a quantity of dimension `𝐌*𝐋^2/(𝐓^2*𝚯)` would be converted to `kg*m^2/(s^2*K)`:

```jldoctest
julia> promote(1.0u"J/K", 1.0u"g*cm^2/s^2/K")
(1.0 kg m^2 K^-1 s^-2, 1.0e-7 kg m^2 K^-1 s^-2)
```

You can however override this behavior by calling [`Unitful.preferunits`](@ref)
at the start of a Julia session, specifically *before* [`Unitful.upreferred`](@ref)
*has been called or quantities have been promoted*.

```@docs
Unitful.preferunits
Unitful.upreferred
```

### Array promotion

Arrays are typed with as much specificity as possible upon creation. consider
the following three cases:

```jldoctest
julia> [1.0u"m", 2.0u"m"]
2-element Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}:
 1.0 m
 2.0 m

julia> [1.0u"m", 2.0u"cm"]
2-element Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}:
 1.0 m
 0.02 m

julia> [1.0u"m", 2.0]
2-element Vector{Quantity{Float64}}:
 1.0 m
 2.0
```

In the first case, an array with a concrete type is created. Good
performance should be attainable. The second case invokes promotion so that an
array of concrete type can be created. The third case falls back to an abstract
type, which cannot be stored efficiently and will incur a performance penalty.
An additional benefit of having a concrete type is that we can dispatch on the
dimensions of the array's elements:

```jldoctest
julia> f(x::AbstractArray{T}) where {T<:Unitful.Length} = sum(x)
f (generic function with 1 method)

julia> f([1.0u"m", 2.0u"cm"])
1.02 m

julia> f([1.0u"g", 2.0u"cm"])
ERROR: MethodError: no method matching f(::Vector{Quantity{Float64}})
[...]
```

## Advanced promotion mechanisms

There are some new types as of Unitful.jl v0.2.0 that enable some fairly sophisticated
promotion logic. Three concrete subtypes of [`Unitful.Units{N,D,A}`](@ref) are defined:
[`Unitful.FreeUnits{N,D,A}`](@ref), [`Unitful.ContextUnits{N,D,P,A}`](@ref), and
[`Unitful.FixedUnits{N,D,A}`](@ref).

Units defined in the Unitful.jl package itself are all `Unitful.FreeUnits{N,D,A}` objects.
The "free" in `FreeUnits` indicates that the object carries no information on its own about
how it should respond during promotion. Other code in Unitful dictates that by default,
quantities should promote to SI units. `FreeUnits` use the promotion mechanisms described
in the above section, [Basic promotion mechanisms](@ref). They used to be called `Units`
in prior versions of Unitful.

### ContextUnits

Sometimes, a package may want to default to a particular behavior for promotion, in the
presence of other packages that may require differing default behaviors. An example would be
a CAD package for nanoscale device design: it makes more sense to promote to nanometers or
microns than to meters. For this purpose we define `Unitful.ContextUnits{N,D,P,A}`. The `P` in
this type signature should be some type `Unitful.FreeUnits{M,D,B}` (the dimensions must be the
same). We refer to this as the "context." `ContextUnits` may be easily instantiated by e.g.
`ContextUnits(nm, μm)` for a `nm` unit that will promote to `μm`. Here's an example:

```jldoctest
julia> μm = Unitful.ContextUnits(u"μm", u"μm")
μm

julia> nm = Unitful.ContextUnits(u"nm", u"μm")
nm

julia> 1.0μm + 1.0nm
1.001 μm
```

If the context does not agree, then we fall back to `FreeUnits`:

```jldoctest
julia> μm = Unitful.ContextUnits(u"μm", u"μm")
μm

julia> nm = Unitful.ContextUnits(u"nm", u"cm")
nm

julia> 1.0μm + 1.0nm
1.001e-6 m
```

Multiplying a `ContextUnits` by a `FreeUnits` yields a
`ContextUnits` object, with the preferred units for the additional dimensions being
determined by calling [`Unitful.upreferred`](@ref) on the `FreeUnits` object:

```jldoctest
julia> mm = Unitful.ContextUnits(u"mm", u"μm")
mm

julia> isa(u"g", Unitful.FreeUnits)
true

julia> upreferred(u"g")
kg

julia> mm*u"g"
g mm

julia> isa(mm*u"g", Unitful.ContextUnits)
true

julia> upreferred(mm*u"g")
kg μm
```

### FixedUnits

Sometimes, there may be times where it is required to disable automatic conversion between
quantities with different units. For this purpose there are `Unitful.FixedUnits{N,D,A}`.
Trying to add or compare two quantities with `FixedUnits` will throw an error, provided the
units are not the same. Note that you can still add/compare a quantity with `FixedUnits` to
a quantity with another kind of units; in that case, the result units (if applicable) are
determined by the `FixedUnits`, overriding the preferred units from `ContextUnits` or
`FreeUnits`. Multiplying `FixedUnits` with any other kind of units returns `FixedUnits`:

```jldoctest
julia> mm_fix = Unitful.FixedUnits(u"mm")
mm

julia> cm_fix = Unitful.FixedUnits(u"cm")
cm

julia> 1mm_fix+2mm_fix
3 mm

julia> 1mm_fix+2u"cm"  # u"cm" is a FreeUnits object.
21 mm

julia> 1mm_fix+2*Unitful.ContextUnits(u"cm", u"cm")
21 mm

julia> isa(mm_fix*u"cm", Unitful.FixedUnits)
true

julia> 1mm_fix+2cm_fix
ERROR: automatic conversion prohibited.
[...]

julia> 1mm_fix == 1mm_fix
true

julia> 1mm_fix == 0.1u"cm"
true

julia> 1mm_fix == 0.1cm_fix
ERROR: automatic conversion prohibited.
[...]
```

Much of this functionality is enabled by `promote_unit` definitions. These are not
readily extensible by the user at this point.

```@docs
    Unitful.promote_unit
```

## Unit cancellation

For multiplication and division, note that powers-of-ten prefixes are significant
in unit cancellation. For instance, `mV/V` is not simplified, although `V/V` is.
Also, `N*m/J` is not simplified: there is currently no logic to decide
whether or not units on a dimensionless quantity seem "intentional" or not.
It is however possible to cancel units manually, by converting the dimensionless
quantity to the [`NoUnits`](@ref) unit. This takes into account different SI-prefixes:
```jldoctest
julia> using Unitful

julia> 1u"kN*m"/4u"J" |> NoUnits
250.0
```


================================================
FILE: docs/src/dates.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Interoperability with the `Dates` standard library

[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.

## Support for `Dates.FixedPeriod`s

The `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.

!!! note
    `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.

Each `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:

```@docs
Unitful.Quantity(::Dates.FixedPeriod)
```

In 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`:

```jldoctest
julia> using Dates: Hour

julia> p = Hour(3)
3 hours

julia> uconvert(u"s", p)
10800 s

julia> p == 180u"minute"
true

julia> p < 1u"d"
true

julia> 5u"s" + p
10805 s

julia> 210u"km" / p
70.0 km hr^-1

julia> unit(p) === u"hr"
true

julia> dimension(p)
𝐓
```

Conversely, 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`:

```jldoctest
julia> using Dates: Day, Hour, Millisecond

julia> Millisecond(1.5u"s")
1500 milliseconds

julia> convert(Hour, 1u"yr")
8766 hours

julia> Day(1u"yr")
ERROR: InexactError: Int64(1461//4)
[...]

julia> round(Day, 1u"yr")
365 days
```

## Support for `Dates.CompoundPeriod`s

The `Dates` standard library provides the `Dates.CompoundPeriod` type to represent sums of periods of different types:

```@repl
using Dates: Day, Second
Day(5) + Second(1)
typeof(ans)
```

Unitful 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`:

```@jldoctest
julia> using Dates: Day, Second

julia> p = Day(5) + Second(1)
5 days, 1 second

julia> uconvert(u"s", p)
432001//1 s

julia> convert(typeof(1.0u"yr"), p)
0.01368928562374832 yr

julia> round(u"d", p)
5//1 d

julia> q = Month(1) + Day(1)  # Month is not a fixed period
1 month, 1 day

julia> uconvert(u"s", q)
ERROR: MethodError: no method matching Quantity{Rational{Int64},𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}}(::Month)
[...]
```

However, not all operations that are defined for `FixedPeriod`s support `CompoundPeriod`s as well.
The reason for that is that a `CompoundPeriod` does not correspond to a specific unit:

```@jldoctest
julia> p = Day(365) + Hour(6)
365 days, 6 hours

julia> unit(p)  # A CompoundPeriod does not have a corresponding unit ...
ERROR: MethodError: no method matching unit(::Dates.CompoundPeriod)
[...]

julia> dimension(p)  # ... but it does have a dimension
𝐓

julia> Quantity(p)  # As a result, there is no Quantity type associated with it ...
ERROR: MethodError: no method matching Quantity(::Int64)
[...]

julia> T = typeof(1.0u"hr"); T(p)  # ... but it can be converted to a concrete time quantity
8766.0 hr
```

Consequently, any operation whose result would depend on the input unit is not supported by `CompoundPeriod`s. For example:

* `+(::Quantity, ::CompoundPeriod)` and `+(::CompoundPeriod, ::Quantity)` error, since the unit of the result depends on the units of both arguments.
* `div(::Quantity, ::CompoundPeriod)` and `div(::CompoundPeriod, ::Quantity)` work, since the result is a dimensionless number.
* `mod(::CompoundPeriod, ::Quantity)` works, but `mod(::Quantity, ::CompoundPeriod)` does not, since the second argument determines the unit of the returned quantity.


================================================
FILE: docs/src/defaultunits.md
================================================
# Pre-defined units and сonstants

In 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.

```
help?> Unitful.kW
  Unitful.kW

  A prefixed unit, equal to 10^3 W.

  Dimension: 𝐋² 𝐌 𝐓⁻³

  See also: Unitful.W.
```

For prefixes, see [below](#Metric-(SI)-Prefixes).


## Base dimensions

### Amount

```@docs
Unitful.𝐍
Unitful.Amount
Unitful.mol
```

### Current

```@docs
Unitful.𝐈
Unitful.Current
Unitful.A
```

### Length

```@docs
Unitful.𝐋
Unitful.Length
Unitful.angstrom
Unitful.cm
Unitful.fm
Unitful.ft
Unitful.inch
Unitful.m
Unitful.mi
Unitful.mil
Unitful.nm
Unitful.yd
```

### Luminosity

```@docs
Unitful.𝐉
Unitful.Luminosity
Unitful.cd
Unitful.lm
```

### Mass

```@docs
Unitful.𝐌
Unitful.Mass
Unitful.dr
Unitful.g
Unitful.gr
Unitful.kg
Unitful.lb
Unitful.oz
Unitful.slug
Unitful.u
```

### Temperature

```@docs
Unitful.𝚯
Unitful.Temperature
Unitful.K
Unitful.Ra
Unitful.°C
Unitful.°F
```

### Time

```@docs
Unitful.𝐓
Unitful.Time
Unitful.d
Unitful.hr
Unitful.minute
Unitful.s
Unitful.wk
Unitful.yr
```

## Derived dimensions

### Acceleration

```@docs
Unitful.Acceleration
Unitful.Gal
Unitful.ge
```

### Area

```@docs
Unitful.Area
Unitful.a
Unitful.ac
Unitful.b
Unitful.ha
```

### BField

```@docs
Unitful.BField
Unitful.Gauss
Unitful.T
```

### Capacitance

```@docs
Unitful.Capacitance
Unitful.F
```

### Charge

```@docs
Unitful.Charge
Unitful.C
```

### DynamicViscosity

```@docs
Unitful.DynamicViscosity
Unitful.P
```

### ElectricalConductance

```@docs
Unitful.ElectricalConductance
Unitful.S
```

### ElectricalResistance

```@docs
Unitful.ElectricalResistance
Unitful.Ω
```

### Energy

```@docs
Unitful.Energy
Unitful.btu
Unitful.cal
Unitful.erg
Unitful.eV
Unitful.J
```

### Force

```@docs
Unitful.Force
Unitful.dyn
Unitful.lbf
Unitful.N
```

### Frequency

```@docs
Unitful.Frequency
Unitful.Bq
Unitful.Hz
Unitful.Hz2π
Unitful.rpm
Unitful.rps
```

### HField

```@docs
Unitful.HField
Unitful.Oe
```

### Inductance

```@docs
Unitful.Inductance
Unitful.H
```

### KinematicViscosity

```@docs
Unitful.KinematicViscosity
Unitful.St
```

### MagneticFlux

```@docs
Unitful.MagneticFlux
Unitful.Mx
Unitful.Wb
```

### MolarFlow

```@docs
Unitful.MolarFlow
Unitful.kat
```

### Molarity

```@docs
Unitful.Molarity
Unitful.M
```

### Power

```@docs
Unitful.Power
Unitful.W
```

### Pressure

```@docs
Unitful.Pressure
Unitful.atm
Unitful.Ba
Unitful.bar
Unitful.kPa
Unitful.Pa
Unitful.psi
Unitful.Torr
```

### Velocity

```@docs
Unitful.Velocity
Unitful.c
```

### Voltage

```@docs
Unitful.Voltage
Unitful.V
```

### Volume

```@docs
Unitful.Volume
Unitful.L
```

## Dimensionless units

```@docs
Unitful.°
Unitful.pcm
Unitful.percent
Unitful.permille
Unitful.pertenthousand
Unitful.ppb
Unitful.ppm
Unitful.ppq
Unitful.ppt
Unitful.rad
Unitful.sr
```

## Logarithmic units

| Unit           | Name                            |
|----------------|---------------------------------|
| `dB`       |        Decibel |
| `B`        |         Bel |
| `Np`       |        Neper |
| `cNp`      |       Centineper |

### Log units related to reference levels
| Unit           | Reference level                            |
|----------------|---------------------------------|
| `dBHz`       |         1Hz |
| `dBm`          |         1mW |
| `dBV`          |         1V |
| `dBu`          |         sqrt(0.6)V |
| `dBμV`        |         1μV |
| `dBSPL`      |         20μPa |
| `dBFS`        |         RootPowerRatio(1) |
| `dBΩ`          |         1Ω |
| `dBS`          |         1S |

## Physical constants

```@docs
Unitful.c0
Unitful.G
Unitful.gn
Unitful.h
Unitful.k
Unitful.me
Unitful.mn
Unitful.mp
Unitful.Na
Unitful.q
Unitful.R
Unitful.R∞
Unitful.Z0
Unitful.ħ
Unitful.ε0
Unitful.μ0
Unitful.μB
Unitful.σ
Unitful.Φ0
```

## Metric (SI) Prefixes

| Prefix | Name | Power of Ten |
|--------|--------|--------|
| y | yocto | -24 |
| z | zepto | -21 |
| a | atto | -18 |
| f | femto | -15 |
| p | pico | -12 |
| n | nano | -9 |
| μ | micro | -6 |
| m | milli | -3 |
| c | centi | -2 |
| d | deci | -1 |
| da | deca | 1 |
| h | hecto | 2 |
| k | kilo | 3 |
| M | mega | 6 |
| G | giga | 9 |
| T | tera | 12 |
| P | peta | 15 |
| E | exa | 18 |
| Z | zetta | 21 |
| Y | yotta | 24 |


================================================
FILE: docs/src/display.md
================================================
# How units are displayed

By default, exponents on units or dimensions are indicated using Unicode superscripts on
macOS and without superscripts on other operating systems. You can set the environment
variable `UNITFUL_FANCY_EXPONENTS` to either `true` or `false` to force using or not using
the exponents. You can also set the `:fancy_exponent` IO context property to either `true`
or `false` to force using or not using the exponents.

```@docs
Unitful.BracketStyle
Unitful.abbr
Unitful.prefix
Unitful.show(::IO, ::Quantity)
Unitful.show(::IO, ::Unitful.Unitlike)
Unitful.showrep
Unitful.showval
Unitful.superscript
```


================================================
FILE: docs/src/extending.md
================================================
# Extending Unitful

## Making your own units package

New units or dimensions can be defined from the Julia REPL or from within
other packages. To avoid duplication of code and effort, it is advised to put
new unit definitions into a Julia package that is then published for others to
use. For an example of how to do this, examine the code in
[`UnitfulUS.jl`](https://github.com/PainterQubits/UnitfulUS.jl), which defines
U.S. customary units. It's actually very easy! Just make sure you read all of
the cautionary notes on this page. If you make a units package for Unitful,
please submit a pull request so that I can provide a link from Unitful's README!

## Some limitations

### Precompilation

When creating new units in a precompiled package that need to persist into
run-time (usually true), it is important that the following make it into your
code:

```julia
function __init__()
    Unitful.register(YourModule)
end
```

By calling [`Unitful.register`](@ref) in your `__init__` function, you tell
Unitful about some internal data required to make Unit conversions work and
also make your units accessible to Unitful's [`@u_str`](@ref) macro. Your unit
symbols should ideally be distinctive to avoid colliding with symbols defined
in other packages or in Unitful. If there is a collision, the [`@u_str`](@ref)
macro will still work, but it will use the unit found in whichever package was
registered most recently, and it will emit a warning every time.

If you use the `@u_str` macro with the units defined in your package, you'll
also need to call `Unitful.register()` at the top level of your package at
compile time.

In the unlikely case that you've used `@dimension`, you will also need the
following incantation:

```julia
const localpromotion = copy(Unitful.promotion)
function __init__()
    Unitful.register(YourModule)
    merge!(Unitful.promotion, localpromotion)
end
```

The definition of `localpromotion` must happen *after all new units
(dimensions) have been defined*.

### Type uniqueness

Currently, when the [`@dimension`](@ref), [`@derived_dimension`](@ref),
[`@refunit`](@ref), or [`@unit`](@ref) macros are used, some unique symbols
must be provided which are used to differentiate types in dispatch. These
are typically the names of dimensions or units (e.g. `Length`, `Meter`, etc.)
One problem that could occur is that if multiple units or dimensions are defined
with the same name, then they will be indistinguishable in dispatch and errors
will result.

I don't expect a flood of units packages to come out, so probably the likelihood
of name collision is pretty small. When defining units yourself, do take care to
use unique symbols, perhaps with the aid of `Base.gensym()` if creating units at
runtime. When making packages, look and see what symbols are used by existing
units packages to avoid trouble.

## Archaic or fictitious unit systems

In the rare event that you want to define physical units which are not
convertible to SI units, you need to do a bit of extra work. To be clear,
such a conversion should always exist, in principle. One can imagine, however,
archaic or fictitious unit systems for which a precise conversion to SI units
is unknown. For example, a [cullishigay](https://en.wikipedia.org/wiki/Cullishigay)
is one-third of a mudi, but only *approximately* 1.25 imperial bushels. There may
be cases where you don't even have an approximate conversion to imperial bushels.
At such a time, you may feel uncomfortable specifying the "base unit" of this
hypothetical unit system in terms of an SI quantity, and may want to
explicitly forbid any attempt to convert to SI units.

One can achieve this by defining new dimensions with the [`@dimension`](@ref) or
[`@derived_dimension`](@ref) macros. The trick is to define dimensions that display
suggestively like physical dimensions, like `𝐋*`, `𝐓*` etc., but are distinct as far
as Julia's type system is concerned. Then, you can use [`@refunit`](@ref) to
base units for these new dimensions without reference to SI. The result will be
that attempted conversion between the hypothetical unit system and SI will fail
with a `DimensionError`, so be sure you provide some hints in how your
new dimensions are displayed to avoid confusing users. It would be confusing
to throw a `DimensionError` when attempting to convert between lengths which are
incompatible in the sense of the previous paragraph, when both lengths display their
dimension as `𝐋`.


================================================
FILE: docs/src/highlights.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Highlighted features

## Dispatch on dimensions

Consider the following toy example, converting from voltage or power ratios to decibels:

```jldoctest
julia> whatsit(x::Unitful.Voltage) = "voltage!"
whatsit (generic function with 1 method)

julia> whatsit(x::Unitful.Length) = "length!"
whatsit (generic function with 2 methods)

julia> whatsit(1u"mm")
"length!"

julia> whatsit(1u"kV")
"voltage!"

julia> whatsit(1u"A" * 2.5u"Ω")
"voltage!"
```

### Dimensions in a type definition

It may be tempting to specify the dimensions of a quantity in a type definition, e.g.

```julia
struct Person
    height::Unitful.Length
    mass::Unitful.Mass
end
```

However, these are abstract types. If performance is important, it may be better
just to pick a concrete `Quantity` type:

```julia
struct Person
    height::typeof(1.0u"m")
    mass::typeof(1.0u"kg")
end
```

You can still create a `Person` as `Person(5u"ft"+10u"inch", 75u"kg")`; the
unit conversion happens automatically.

## Making new units and dimensions

You can make new units using the [`@unit`](@ref) macro on the fly:

```jldoctest
julia> @unit yd5 "yd5" FiveYards 5u"yd" false
yd5
```

## Arrays

Promotion is used to create arrays of a concrete type where possible, such
that arrays of unitful quantities are stored efficiently in memory. However,
if necessary, arrays can hold quantities with different dimensions, even
mixed with unitless numbers. Doing so will suffer a performance penalty compared
with the fast performance attainable with an array of concrete type
(e.g. as resulting from `[1.0u"m", 2.0u"cm", 3.0u"km"]`). However, it could be useful
in toy calculations for
[general relativity](https://en.wikipedia.org/wiki/Metric_tensor_(general_relativity))
where some conventions yield matrices with mixed dimensions:

```jldoctest
julia> using LinearAlgebra

julia> Diagonal([-1.0u"c^2", 1.0, 1.0, 1.0]);
```

## Logarithmic units

```jldoctest
julia> uconvert(u"mW*s", 20u"dBm/Hz")
100.0 s mW
```

## Units with rational exponents

```jldoctest
julia> 1.0u"V/sqrt(Hz)"
1.0 V Hz^-1/2
```

## Exact conversions respected

```jldoctest
julia> uconvert(u"ft",1u"inch")
1//12 ft
```


================================================
FILE: docs/src/index.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Unitful.jl

A Julia package for physical units. Available
[here](https://github.com/JuliaPhysics/Unitful.jl). Inspired by:

- [SIUnits.jl](https://github.com/keno/SIUnits.jl)
- [EngUnits.jl](https://github.com/dhoegh/EngUnits.jl)
- [Units.jl](https://github.com/timholy/Units.jl)

We want to support not only SI units but also any other unit system. We also
want to minimize or in some cases eliminate the run-time penalty of units.
There should be facilities for dimensional analysis. All of this should
integrate easily with the usual mathematical operations and collections
that are defined in Julia.

## Quick start

- This package requires Julia 1.0. Older versions will not be supported.
- `] add Unitful`
- `using Unitful`

Unitful aims for generality, but has some useful functionality out of the box.
- Base dimensions like length, mass, time, etc. are defined.
- Derived dimensions like volume, energy, momentum, etc. are defined.
- Base and derived SI units with their power-of-ten prefixes are defined.
- Some other common units are defined, without power-of-ten prefixes.
- Sensible default promotion behavior is specified.

Take a look at `src/pkgdefaults.jl` for a complete list. Note that some unit
abbreviations conflict with other definitions or syntax:

- `inch` is used instead of `in`, since `in` conflicts with Julia syntax
- `minute` is used instead of `min`, since `min` is a commonly used function
- `hr` is used instead of `h`, since `h` is revered as the Planck constant
- `hbar` is hectobars in the SI system, so `ħ` is used for the reduced Plank
  constant

## Important note on namespaces

Units, dimensions, and fundamental constants are not exported from Unitful.
This is to avoid proliferating symbols in your namespace unnecessarily. You can
retrieve them from Unitful in one of three ways:

1. Use the [`@u_str`](@ref) string macro.
2. Explicitly import from the `Unitful` package to bring specific symbols
   into the calling namespace.
3. `using Unitful.DefaultSymbols` will bring the following symbols into the
   calling namespace:
     - Dimensions `𝐋,𝐌,𝐓,𝐈,𝚯,𝐉,𝐍` for length, mass, time, current, temperature,
       luminosity, and amount, respectively.
     - Base and derived SI units, with SI prefixes (except for `cd`, which conflicts
       with `Base.cd`)
     - `°` (degrees)
  If you have been using the [SIUnits.jl](https://github.com/keno/SIUnits.jl)
  package, this is not unlike typing `using SIUnits.ShortUnits` with that package.

## Usage examples

```@meta
DocTestSetup = quote
    using Unitful
    °C = Unitful.°C
    °F = Unitful.°F
    Ra = Unitful.Ra
    K = Unitful.K
    μm = Unitful.μm
    m = Unitful.m
    hr = Unitful.hr
    minute = Unitful.minute
    s = Unitful.s
    F = Unitful.F
end
```

```jldoctest
julia> 1u"kg" == 1000u"g"             # Equivalence implies unit conversion
true

julia> !(1u"kg" === 1000u"g")         # ...and yet we can distinguish these...
true

julia> 1u"kg" === 1u"kg"              # ...and these are indistinguishable.
true
```

In the next examples we assume we have brought some units into our namespace,
e.g. `const m = u"m"`, etc.

```jldoctest
julia> uconvert(°C, 212°F)
100//1 °C

julia> uconvert(μm/(m*Ra), 9μm/(m*K))
5//1 μm m^-1 Ra^-1

julia> mod(1hr+3minute+5s, 24s)
17 s
```

One useful interactive function is being able to convert to preferred (in this case SI) units. 

```jldoctest
julia> upreferred(F/m)
A^2 s^4 kg^-1 m^-3
```

!!! note
    Quantities in `°C` or `⁠°F` always unit-convert under an affine transformation that takes
    their relative scales into account. To avoid ambiguities that can lead to incorrect
    results, the units `°C` and `°F` cannot be used in Unitful to represent temperature
    differences. Fortunately, `1°C - 0°C == 1K` and `1°F - 0°F == 1Ra`, so the absolute
    temperature scales Kelvin (`K`) and Rankine (`Ra`) can be used easily to represent
    temperature differences.

See `test/runtests.jl` for more usage examples.

## About the logo

The 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,
when it was replaced by a definition based on the Planck constant, the speed of light, and the ground-state hyperfine transition frequency of ¹³³Cs.


================================================
FILE: docs/src/latexify.md
================================================
# Latexify extension

Unitful has an extension for [Latexify](https://github.com/korsbo/Latexify.jl), which was formerly implemented as a separate package called UnitfulLatexify.jl.

The default usage is pretty intuitive:

```@setup main
using LaTeXStrings # for some manual pretty-printing
```

```@example main
using Unitful, Latexify

a = 9.82u"m/s^2"
t = 4u"s"
x = a*t^2

latexify(x)
```

or more usefully:

```@example main
latexify(:(x = a*t^2 = $x))
```

This of course also works for `Units` objects by themselves:

```@example main
latexify(u"kg*m")
```

Some more usage examples:

![](assets/latex-examples.png)


## Arrays

Because Latexify is recursive, an array of unitful quantities is shown as
expected:


```@example main
latexify([12u"m", 1u"m^2", 4u"m^3"])
LaTeXString("\$" * chopsuffix(chopprefix(ans, "\\begin{equation}\n"), "\n\\end{equation}\n") * "\$") # hide
```

A special case is an array where all elements have the same unit, and here
the extension does some extra work:
```@example main
latexify([1, 2, 3]u"cm")
LaTeXString("\$" * chopsuffix(chopprefix(ans, "\\begin{equation}\n"), "\n\\end{equation}\n") * "\$") # hide
```


## siunitx.sty

If you are exporting your numbers to an actual LaTeX document, you will of
course want to use the commands from `siunitx.sty` rather than the `\mathrm`
style 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
`\qty{8}{s.m/kg}`. Like other Latexify keywords, this can be set to be a default
by using `set_default(fmt=SiunitxNumberFormatter())`, or given with each latexification
command:

```@example main
latexify(612.2u"nm"; fmt=SiunitxNumberFormatter()) # This will not render right without the `siunitx` package
print(ans) # hide
```

### Lists

Another thing that `siunitx` does uniquely is lists and ranges of quantities.
To get `siunitx`'s list behavior, pass a tuple instead of an array;
if you want a tuple to be written as an array instead, use `collect(x)` or `[x...]` to convert it into an array first.

```@example main
latexify((1, 2, 3).*u"m")
print(ans) # hide
```
```@example main
latexify((1, 2, 3).*u"m"; fmt=SiunitxNumberFormatter())
print(ans) # hide
```
```@example main
latexify(collect((1, 2, 3).*u"m"); fmt=SiunitxNumberFormatter())
print(ans) # hide
```


## Plots labels

This extension also interfaces with `Plots` by way of implementing a two-argument `(label, unit)` recipe:

```@example main
latexify("v", u"km/s")
```

This enables this dreamlike example:

```@example plot
using Unitful, Plots, Latexify 
gr()
default(fontfamily="Computer Modern")

m = randn(10)u"kg"
v = randn(10)u"m/s"
plot(m, v; xguide="\\mathrm{mass}", yguide="v_x", unitformat=latexify)
```

This format, ``v_x\;\left/\;\mathrm{m}\,\mathrm{s}^{-1}\right.``, is subject to personal
preference. A couple other defaults are provided:
- `:slash`, ``v_x\;\left/\;\mathrm{m}\,\mathrm{s}^{-1}\right.``
- `:round`, ``v_x\;\left(\mathrm{m}\,\mathrm{s}^{-1}\right)``
- `:square`, ``v_x\;\left[\mathrm{m}\,\mathrm{s}^{-1}\right]``
- `:frac`, ``\frac{v_x}{\mathrm{m}\,\mathrm{s}^{-1}}``

To use these in a plot call, either pass a function like 
```
(l,u) -> latexify(l, u; labelformat=:slash)` 
```
or call `Latexify.set_default(labelformat=:square)`, then pass `latexify` as your unitformat.

```@example plot
args = (m, v)
kwargs = (xguide="\\mathrm{mass}", yguide="v_x", legend=false)
Latexify.set_default(labelformat=:square)
plot(
	plot(args...; kwargs..., unitformat=(l,u)->latexify(l, u, labelformat=:slash)),
	plot(args...; kwargs..., unitformat=(l, u)->latexify(l, u, labelformat=:round)),
	plot(args...; kwargs..., unitformat=latexify),
	plot(args...; kwargs..., unitformat=(l, u)->latexify(l, u, labelformat=:frac)),
	plot(args...; kwargs..., unitformat=(l, u)->string("\$", l, " \\rightarrow ", latexraw(u), "\$")),
)
```

## Pluto notebooks
One use case is in Pluto notebooks, where you can
write

```julia
Markdown.parse("""
The period is $(@latexrun T = $(2.5u"ms")), so the frequency is $(@latexdefine f = 1/T post=u"kHz").
""")
```
which renders as

> The period is $T = 2.5\;\mathrm{ms}$, so the frequency is $f = \frac{1}{T} = 0.4\;\mathrm{kHz}$.

Note that the quantity has to be interpolated (put inside a
dollar-parenthesis), or Latexify will interpret it as a multiplication between
a number and a call to `@u_str`.


## Per-modes

In mathrm-mode, one might prefer ``\mathrm{J}\,/\,\mathrm{kg}`` or
``\frac{\mathrm{J}}{\mathrm{kg}}`` over ``\mathrm{J}\,\mathrm{kg}^{-1}``. This
can be achieved by supplying `permode=:slash` or `permode=:frac` respectively, rather than the default `permode=:power`.

These will have no effect with `SiunitxNumberFormatter`, because the latex package handles
this for you, and you can set it in your document.

## New siunitx syntax

The new syntax from `siunitx v3` (`\qty, \unit` rather
than `\SI, \si`) is used by default. If you cannot upgrade `siunitx`, there's the option
to use `fmt=SiunitxNumberFormatter(version=2)`.

## A more complete list of defined units

Below is a poorly scraped list of units defined in `Unitful` and what comes out
if you run it through `latexify`. Feel free to create an issue if there's a
unit missing or being incorrectly rendered (and suggest a better ``\LaTeX``
representation if you know one).

![](assets/latex-allunits.png)


================================================
FILE: docs/src/logarithm.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Logarithmic scales

!!! note 

    Logarithmic scales should be considered experimental 
    because they break some of the basic assumptions about equality and hashing 
    (see [#402](https://github.com/JuliaPhysics/Unitful.jl/issues/402))

Unitful provides a way to use logarithmically-scaled quantities. Some
compromises have been made in striving for logarithmic quantities to be both usable and
consistent. In the following discussion, for pedagogical purposes, we will assume prior
familiarity with the definitions of `dB` and `dBm`.

## Constructing logarithmic quantities

Left- or right-multiplying a pure number by a logarithmic "unit", whether dimensionful or
dimensionless, is short-hand for constructing a logarithmic quantity.

```jldoctest
julia> 3u"dB"
3 dB

julia> 3u"dBm"
3.0 dBm

julia> u"dB"*3 === 3u"dB"
true
```

Currently implemented are `dB`, `B`, `dBm`, `dBV`, `dBu`, `dBμV`, `dBSPL`, `dBFS`, `cNp`,
`Np`.

One can also construct logarithmic quantities using the `@dB`, `@B`, `@cNp`, `@Np` macros to
use an arbitrary reference level:

```jldoctest
julia> using Unitful: mW, V

julia> @dB 10mW/mW
10.0 dBm

julia> @dB 10V/V
20.0 dBV

julia> @dB 3V/4V
-2.498774732165999 dB (4 V)

julia> @Np ℯ*V/V    # ℯ = 2.71828...
1.0 Np (1 V)
```

These macros are exported by default since empirically macros are defined less often than
variables and generic functions. When using the macros, the levels are constructed at parse
time. The scales themselves are callable as functions if you need to construct a level that
way (they are not exported):

```jldoctest
julia> using Unitful: dB, mW, V

julia> dB(10mW,mW)
10.0 dBm
```

In calculating the logarithms, the log function appropriate to the scale in question is used
(`log10` for decibels, `log` for nepers).

There is an important difference in these two approaches to constructing logarithmic
quantities. When we construct `0dBm`, the power in `mW` is calculated and stored,
resulting in a lossy floating-point conversion. This can be avoided by constructing
`0 dBm` as `@dB 1mW/mW`.

It is important to keep in mind that the reference level is just used to calculate the
logarithms, and nothing more. When there is ambiguity about what to do, we fall back
to the underlying linear quantities, paying no mind to the reference levels:

```jldoctest
julia> using Unitful: mW

julia> (@dB 10mW/1mW) + (@dB 10mW/2mW)
20 mW
```

Addition will be discussed more later.

Note that logarithmic "units" can only multiply or be multiplied by pure numbers and linear
units, not other logarithmic units or quantities. This is done to avoid issues with
commutativity and associativity, e.g. `3*dB*m^-1 == (3dB)/m`, but `3*m^-1*dB == (3m^-1)*dB`
does not make much sense. This is because `dB` acts more like a constructor than a proper
unit.

The `@dB` and `@Np` macros will fail if either a dimensionless number or a ratio of
dimensionless numbers is used. This is because the ratio could be of power quantities or of
root-power quantities, leading to ambiguities. After all, usually it is the ratio that is
dimensionless, not the numerator and denominator that make up the ratio. In some cases
it may nonetheless be convenient to have a dimensionless reference level. By providing an
extra `Bool` argument to these macros, you can explicitly choose whether the resulting ratio
should be considered a "root-power" or "power" ratio. You can only do this for dimensionless
numbers:

```jldoctest
julia> @dB 10/1 true   # is a root-power (amplitude) ratio
20.0 dBFS

julia> @dB 10/1 false  # is not a root-power ratio; is a power ratio
10.0 dB (power ratio with reference 1)
```

Note that `dBFS` is defined to represent amplitudes relative to 1 in `dB`, hence the
custom display logic.

Also, you can of course use functions instead of macros:

```jldoctest
julia> using Unitful: dB, mW

julia> dB(10,1,true)
20.0 dBFS

julia> dB(10mW,mW,true)
ERROR: ArgumentError: when passing a final Bool argument, this can only be used with dimensionless numbers.
[...]
```

### Logarithmic quantities with no reference level specified

Logarithmic quantities with no reference level specified typically represent some amount of
gain or attenuation, i.e. a ratio which is dimensionless. These can be constructed as,
for example, `10*dB`, which displays similarly (`10 dB`). The type of this kind of
logarithmic quantity is:

```@docs
    Unitful.Gain
```

One might expect that any gain / attenuation factor should be convertible to a pure number,
that is, to `x == y/z` if you had `10*log10(x)` dB. However, it turns out that in dB, a ratio
of powers is defined as `10*log10(y/z)`, but a ratio of voltages or other root-power
quantities is defined as `20*log10(y/z)`. Clearly, converting back from decibels to a real
number is ambiguous, and so we have not implemented automatic promotion to avoid incorrect
results. You can use [`Unitful.uconvertp`](@ref) to interpret a `Gain` as a ratio of power
quantities (hence the `p` in `uconvertp`), or [`Unitful.uconvertrp`](@ref) to interpret as
a ratio of root-power (field) quantities.

### "Dimensionful" logarithmic quantities?

In this package, quantities with units like `dBm` are considered to have the dimension of
power, even though the expression `P(dBm) = 10*log10(P/1mW)` is dimensionless and formed
from a dimensionless ratio. Practically speaking, these kinds of logarithmic quantities are
fungible whenever they share the same dimensions, so it is more convenient to adopt this
convention (people refer to `dBm/Hz` as a power spectral density, etc.) Presumably, one
would like to have `10dBm isa Unitful.Power` for dispatch too. Therefore, in the following
discussion, we will shamelessly (okay, with some shame) speak of dimensionful logarithmic
quantities, or `Level`s for short:

```@docs
    Unitful.Level
```

Actually, the defining characteristic of a `Level` is that it has a reference level,
which may or may not be dimensionful. It usually is, but is not in the case of e.g. `dBFS`.

Finally, for completeness we note that both `Level` and `Gain` are subtypes of `LogScaled`:

```@docs
    Unitful.LogScaled
```

## Multiplication rules

Multiplying a dimensionless logarithmic quantity by a pure number acts as like it does for
linear quantities:

```jldoctest
julia> 3u"dB" * 2
6 dB

julia> 2 * 0u"dB"
0 dB
```

Justification by example: consider the example of the exponential attenuation of a signal on
a lossy transmission line. If the attenuation goes like $10^{-kx}$, then the (power)
attenuation in dB is $-10kx$. We see that the attenuation in dB is linear in length. For an
attenuation constant of 3dB/m, we better calculate 6dB for a length of 2m.

Multiplying a dimensionful logarithmic quantity by a pure number acts differently than
multiplying a gain/attenuation by a pure number. Since `0dBm == 1mW`, we better have that
`0dBm * 2 == 2mW`, implying:

```jldoctest
julia> 0u"dBm" * 2
3.010299956639812 dBm
```

Logarithmic quantities can only be multiplied by pure numbers, linear units, or quantities,
but not logarithmic "units" or quantities.  When a logarithmic quantity is multiplied by a
linear quantity, the logarithmic quantity is linearized and multiplication proceeds as
usual:

```jldoctest
julia> (0u"dBm") * (1u"W")
1.0 mW W
```

The previous example returns a floating point value because in constructing the level
`0 dBm`, the power in `mW` is calculated and stored, entailing a floating point
conversion. This can be avoided by constructing `0 dBm` as `@dB 1mW/mW`:

```jldoctest
julia> (@dB 1u"mW"/u"mW") * (1u"W")
1 mW W
```

We refer to a quantity with both logarithmic "units" and linear units as a mixed quantity.
For mixed quantities, the numeric value associates with the logarithmic unit, and the
quantity is displayed in a way that makes this explicit:

```jldoctest
julia> (0u"dBm")/u"Hz"
[0.0 dBm] Hz^-1

julia> (0u"dB")/u"Hz"
[0 dB] Hz^-1

julia> 0u"dB/Hz"
[0 dB] Hz^-1
```

Mathematical operations are forwarded to the logarithmic part, so that for example,
`100*((0dBm)/s) == (20dBm)/s`. We allow linear units to commute with logarithmic quantities
for convenience, though the association is understood (e.g. `s^-1*(3dBm) == (3dBm)/s`).

The behavior of multiplication is summarized in the following table, with entries marked by
† indicating prohibited operations.

```@eval
using Latexify, Unitful
head = ["10", "Hz^-1", "dB", "dBm", "1/Hz", "1mW", "3dB", "3dBm"]
side = ["*"; "**" .* head .* "**"]
quantities = uparse.(head)
tab = fill("", length(head), length(head))
for col = eachindex(head), row = 1:col
    try
        tab[row, col] = sprint(show, quantities[row] * quantities[col], context = :compact => true)
    catch
        if quantities[row] === u"1/Hz" && quantities[col] === u"3dB"
            tab[row, col] = "† ‡"
        else
            tab[row, col] = "†"
        end
    end
end
mdtable(tab, latex=false, head=head, side=side)
```

‡: `1/Hz * 3dB` could be allowed, technically, but we throw an error if it's unclear whether
a quantity is a root-power or power quantity:

```jldoctest
julia> u"1/Hz" * u"3dB"
ERROR: undefined behavior. Please file an issue with the code needed to reproduce.
```

On the other hand, if it can be determined that a power quantity or root-power quantity
is being multiplied by a gain, then the gain is interpreted as a power ratio or root-power
ratio, respectively:

```jldoctest
julia> 1u"mW" * 20u"dB"
100.0 mW

julia> 1u"V" * 20u"dB"
10.0 V
```

## Addition rules

We can add logarithmic quantities without reference levels specified (`Gain`s):

```jldoctest
julia> 20u"dB" + 20u"dB"
40 dB
```

The numbers out front of the `dB` just add: when we talk about gain or attenuation,
we work in logarithmic units so that we can add rather than multiply gain factors. The same
behavior holds when we add a `Gain` to a `Level` or vice versa:

```jldoctest
julia> 20u"dBm" + 20u"dB"
40.0 dBm
```

In the case where you have differing logarithmic scales for the `Level` and the `Gain`,
the logarithmic scale of the `Level` is used for the result:

```jldoctest
julia> 10u"dBm" - 1u"Np"
1.3141103619349632 dBm
```

For logarithmic quantities with the same reference levels, the numbers out in front do not
simply add:

```jldoctest
julia> 20u"dBm" + 20u"dBm"
23.010299956639813 dBm

julia> 2 * 20u"dBm"
23.010299956639813 dBm
```

This is because `dBm` represents a power, ultimately. If we have some amount of power and
we double it, we'd better get roughly `3 dB` more power. Note that the juxtaposition `20dBm`
will ensure that 20 dBm is constructed before multiplication by 2 in the above example.
If you were to type `2*20*dBm`, you'd get 40 dBm.

If the reference levels differ but both levels represent a power, we fall back to linear
quantities:

```jldoctest
julia> 20u"dBm" + @dB 1u"W"/u"W"
1.1 kg m^2 s^-3
```
i.e. `1.1 W`.

Rules for addition are summarized in the following table, with entries marked by †
indicating prohibited operations.

```@eval
using Latexify, Unitful
head = ["100", "20dB", "1Np", "10.0dBm", "10.0dBV", "1mW"]
side = ["+"; "**" .* head .* "**"]
quantities = uparse.(head)
tab = fill("", length(head), length(head))
for col = eachindex(head), row = 1:col
    try
        tab[row, col] = sprint(show, quantities[row] + quantities[col], context = :compact => true)
    catch
        tab[row, col] = "†"
    end
end
mdtable(tab, latex=false, head=head, side=side)
```

Notice that we disallow implicit conversions between dimensionless logarithmic quantities
and real numbers. This is because the results can depend on promotion rules in addition to
being ambiguous because of the root-power vs. power ratio issue. If `100 + 10dB` were
evaluated as `20dB + 10dB == 30dB`, then we'd get `1000`, but if it were evaluated as
`100+10`, we'd get `110`.

Also, although it is possible in principle to add e.g. `20dB + 1Np`, notice that we have
not implemented that because it is unclear whether the result should be in nepers or
decibels, and it is also unclear how to handle that question more generally as other
logarithmic scales are introduced.

## Conversion

As alluded to earlier, conversions can be tricky because so-called logarithmic units are not
units in the conventional sense.

You may use [`linear`](@ref) to convert to a linear scale when you have a `Level` or
`Quantity{<:Level}` type. There is a fallback for `Number`, which just returns the number.

```jldoctest
julia> linear(@dB 10u"mW"/u"mW")
10 mW

julia> linear(20u"dBm/Hz")
100.0 mW Hz^-1

julia> linear(30u"W")
30 W

julia> linear(12)
12
```

Linearizing a `Quantity{<:Gain}` or a `Gain` to a real number is ambiguous, because the real
number may represent a ratio of powers or a ratio of root-power (field) quantities. We
implement [`Unitful.uconvertp`](@ref) and [`Unitful.uconvertrp`](@ref) which may be
thought of as disambiguated `uconvert` functions. There is a one argument version that
assumes you are converting to a unitless number. These functions can take either a `Gain`
or a `Real` so that they may be used somewhat generically.

```jldoctest
julia> uconvertrp(NoUnits, 20u"dB")
10.0

julia> uconvertp(NoUnits, 20u"dB")  
100.0

julia> uconvertp(u"dB", 100)
20.0 dB

julia> uconvertp(u"Np", ℯ^2)
1.0 Np

julia> uconvertrp(u"Np", ℯ)
1//1 Np
```

## Notation

This package displays logarithmic quantities using shorthand like `dBm` where available.
This should probably not be done in polite company. To quote "Guide for the Use of the
International System of Units (SI)," NIST Special Pub. 811 (2008):

> The rules of Ref. [5: IEC 60027-3] preclude, for example, the use of the symbol dBm to
> indicate a reference level of power of 1 mW. This restriction is based on the rule of Sec.
> 7.4, which does not permit attachments to unit symbols.

The authorities say the reference level should always specified. In practice, this hasn't
stopped the use of `dBm` and the like on commercially available test equipment. Dealing with
these units is unavoidable in practice. When no shorthand exists, we follow NIST's advice in
displaying logarithmic quantities:

> When such data are presented in a table or in a figure, the following condensed notation
> may be used instead: -0.58 Np (1 μV/m); 25 dB (20 μPa).

## Custom logarithmic scales

```@docs
    Unitful.@logscale
```

## API

```@docs
    Unitful.linear
    Unitful.logunit
    Unitful.reflevel
    Unitful.uconvertp
    Unitful.uconvertrp
```


================================================
FILE: docs/src/manipulations.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
    using InverseFunctions
end
```
# Manipulating units

## Unitful string macro

```@docs
Unitful.@u_str
Unitful.register
```

## Dimension and unit inspection

We define a function [`dimension`](@ref) that turns, for example, `acre^2` or `1*acre^2`
into `𝐋^4`. We can usually add quantities with the same dimension, regardless of specific
units (`FixedUnits` cannot be automatically converted, however). Note that dimensions cannot
be determined by powers of the units: `ft^2` is an area, but so is `ac^1` (an acre).

There is also a function [`unit`](@ref) that turns, for example, `1*acre^2` into `acre^2`.
You can then query whether the units are `FreeUnits`, `FixedUnits`, etc.

```@docs
Unitful.unit
Unitful.dimension
```

## Unit stripping

```@docs
Unitful.ustrip
```

## Unit multiplication

```@docs
*(::Unitful.Units, ::Unitful.Units...)
*(::Unitful.Dimensions, ::Unitful.Dimensions...)
```


================================================
FILE: docs/src/newunits.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Defining new units

!!! note
    Logarithmic units should not be used in the `@refunit` or `@unit` macros described below.
    See the section on logarithmic scales for customization help.

The package automatically generates a useful set of units and dimensions in the
`Unitful` module in `src/pkgdefaults.jl`.

If a different set of default units or dimensions is desired, macros for
generating units and dimensions are provided. To create new units
interactively, most users will be happy with the [`@unit`](@ref) macro
and the [`Unitful.register`](@ref) function, which makes units defined in a module
available to the [`@u_str`](@ref) string macro.

An example of defining units in a module:

```jldoctest
julia> module MyUnits; using Unitful; @unit myMeter "m" MyMeter 1u"m" false; end
MyUnits

julia> using Unitful

julia> u"myMeter"
ERROR: LoadError:
[...]

julia> Unitful.register(MyUnits);

julia> u"myMeter"
m
```

You could have also called `Unitful.register` inside the `MyUnits` module; the choice is
somewhat analogous to whether or not to export symbols from a module, although the symbols
are never really exported, just made available to the `@u_str` macro. If you want to make a
precompiled units package, rather than define a module at the REPL,
see [Making your own units package](@ref).

You can also define units directly in the `Main` module at the REPL:

```jldoctest
julia> using Unitful

julia> Unitful.register(@__MODULE__);

julia> @unit M "M" Molar 1u"mol/L" true;

julia> 1u"mM"
1 mM
```

A note for the experts: Some care should be taken if explicitly creating
[`Unitful.Units`](@ref) objects. The ordering of [`Unitful.Unit`](@ref) objects
inside a tuple matters for type comparisons. Using the unary multiplication
operator on the `Units` object will return a "canonically sorted" `Units` object.
Indeed, this is how we avoid ordering issues when multiplying quantities together.

## Defining units in precompiled packages

See [Precompilation](@ref).

## Useful functions and macros
```@docs
Unitful.@dimension
Unitful.@derived_dimension
Unitful.@refunit
Unitful.@unit
Unitful.@affineunit
```

## Internals
```@docs
Unitful.@prefixed_unit_symbols
Unitful.@unit_symbols
Unitful.basefactor
```


================================================
FILE: docs/src/temperature.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
    using Unitful:AffineError
end
```
# Temperature scales

Temperatures require some care. Temperature scales like `K` and `Ra` are thermodynamic
temperature scales, with zero on the scale corresponding to absolute zero. Unit conversions
between thermodynamic or absolute temperatures are done by multiplying conversion factors,
as usual. Also in common use are temperature scales like `°C` or `°F`, which are defined
relative to arbitrary offsets. For example, in the case of `°C`, zero on the scale is the
freezing point of water, not absolute zero. To convert between relative temperature scales,
an affine transformation is required. Absolute and relative temperatures can be
distinguished by type to avoid ambiguities that could yield erroneous or unexpected results.
On relative temperature scales, problems can arise because e.g. `0°C + 0°C` could mean `0°C`
or `273.15°C`, depending on whether the operands are variously interpreted as temperature
differences or as absolute temperatures. On thermodynamic temperature scales, there is no
ambiguity.

## Temperatures on absolute scales

Unit conversions between temperatures on absolute scales like Kelvin or Rankine are done in
the usual way by multiplication of a scale factor. For example, we have:

```jldoctest
julia> uconvert(u"K", 1u"Ra")
5//9 K
```

We can identify absolute temperatures using the `Unitful.AbsoluteScaleTemperature` type
alias:

```jldoctest
julia> 1u"K" isa Unitful.AbsoluteScaleTemperature
true
```

## Temperatures on relative scales

Unit conversions between temperatures on relative scales like Celsius or Fahrenheit involve
an affine transformation, that is, a scaling plus some translation (scale offset). In
Unitful, relative scale temperatures are considered to have the same dimension as absolute
scale temperatures, as expected. However, temperatures on relative and absolute scales are
distinguished by the type of the [`Unitful.Units`](@ref) object (and therefore the type of
the [`Unitful.Quantity`](@ref) object).

```jldoctest
julia> uconvert(u"°C", 32u"°F")
0//1 °C
```

We can identify relative scale temperatures using the `Unitful.RelativeScaleTemperature`
type alias, e.g.:

```jldoctest
julia> 1u"°C" isa Unitful.RelativeScaleTemperature
true
```

Some operations are not well defined with relative scale temperatures, and therefore throw
an `Unitful.AffineError` (please report any unexpected behavior on the GitHub issue
tracker).

```jldoctest
julia> 32u"°F" + 1u"°F"
ERROR: AffineError: an invalid operation was attempted with affine quantities: 32 °F + 1 °F
[...]

julia> 32u"°F" * 2
ERROR: AffineError: an invalid operation was attempted with affine quantities: 32 °F*2
[...]
```

There is a general mechanism for making units that indicate quantities should unit-convert
under some affine transformation. While the usual use case is for relative scale
temperatures, nothing in the implementation limits it as such. Accordingly, relative scale
temperatures are considered to be [`Unitful.AffineQuantity`](@ref) objects with dimensions
of temperature. The units on "affine quantities" are [`Unitful.AffineUnits`](@ref) objects.

Making your own affine units typically requires two steps. First, define the absolute unit
using the [`Unitful.@unit`](@ref) macro. Second, use the [`Unitful.@affineunit`](@ref) macro
to make a corresponding affine unit. As an example, this is how `Ra` and `°F` are
implemented:

```julia
@unit Ra "Ra" Rankine (5//9)*K false
@affineunit °F "°F" (45967//100)Ra
```

The preferred unit for promoting temperatures is usually `K` when using
[`Unitful.FreeUnits`](@ref).

```@docs
Unitful.AffineUnits
Unitful.AffineQuantity
Unitful.ScalarUnits
Unitful.ScalarQuantity
Unitful.absoluteunit
```


================================================
FILE: docs/src/trouble.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Troubleshooting

## Why do unit conversions yield rational numbers sometimes?

We use rational numbers in this package to permit exact conversions
between different units where possible. As an example, one inch is exactly equal
to 2.54 cm. However, in Julia, the floating-point `2.54` is not equal to
`254//100`. As a consequence, `1inch != 2.54cm`, because Unitful respects exact
conversions. To test for equivalence, instead use `≈` (`\approx`
tab-completion).

### But I want a floating point number...

`float(x)` is defined for [`Unitful.Quantity`](@ref) types,
and is forwarded to the underlying numeric type (units are not affected).

We may consider adding an option in the defaults to turn on/off use of `Rational`
numbers. They permit exact conversions, but they aren't preferred as a result
type in much of Julia Base (consider that `inv(2) === 0.5`, not `1//2`).

## Exponentiation

Most operations with this package should in principle suffer little performance
penalty if any at run time. An exception to this is rule is exponentiation.
Since units and their powers are encoded in the type signature of a
[`Unitful.Quantity`](@ref) object, raising a `Quantity` to some power, which is
just some run-time value, necessarily results in different result types.
This type instability could impact performance:

```jldoctest
julia> square(x) = (p = 2; x^p)
square (generic function with 1 method)
```

In Julia, constant literal integers are lowered specially for exponentiation.
(See Julia PR [#20530](https://github.com/JuliaLang/julia/pull/20530) for details.)
In this case, type stability can be maintained:

```jldoctest
julia> square(x) = x^2
square (generic function with 1 method)
```

Because the functions `inv`, `sqrt`, and `cbrt` are raising a `Quantity` to a fixed
power (-1, 1/2, and 1/3, respectively), we can use a generated function to ensure
type stability in these cases. Also note that squaring a `Quantity` can be
type-stable if done as `x*x`.

## Promotion with dimensionless numbers

Most of the time, you are only permitted to do sensible operations in Unitful.
With dimensionless numbers, some of the safe logic breaks down. Consider for
instance that `μm/m` and `rad` are both dimensionless units, but kind of have
nothing to do with each other. It would be a little weird to add them. Nonetheless,
we permit this to happen since they have the same dimensions. Otherwise, we
would have to special-case operations for two dimensionless quantities rather
than dispatching on the empty dimension.

The result of addition and subtraction with dimensionless but unitful numbers
is always a pure number with no units. With angles, `1 rad` is essentially just
`1`, giving sane behavior:

```jldoctest
julia> π/2*u"rad"+90u"°"
3.141592653589793
```

## Broken display of dimension characters in the REPL

On some terminals with some fonts, dimension characters such as `𝐌` are displayed as an
empty box. Setting a wider font spacing in your terminal settings can solve this problem.

## I have a different problem

Please raise an issue. This package is in development and there may be bugs.
Feature requests may also be considered and pull requests are welcome.


================================================
FILE: docs/src/types.md
================================================
```@meta
DocTestSetup = quote
    using Unitful
end
```
# Types

## Overview
We define a [`Unitful.Unit{U,D}`](@ref) type to represent a unit (`U` is a symbol,
like `:Meter`, and `D` keeps track of dimensional information).
Fields of a `Unit` object keep track of a rational exponents and a power-of-ten
prefix. We don't allow arbitrary floating point exponents of units because they
probably aren't very useful. The prefixes on units (e.g. `nm` or `km`) may help
to avoid overflow issues and general ugliness.

Usually, the user interacts only with `Units` objects, not `Unit` objects.
This is because generically, more than one unit is needed to describe a quantity.
An abstract type [`Unitful.Units{N,D,A}`](@ref) is defined, where `N` is always a tuple
of `Unit` objects, `D` is a [`Unitful.Dimensions{N}`](@ref) object such as `𝐋`, the
object representing the length dimension, and `A` is a translation for affine quantities.

Subtypes of `Unitful.Units{N,D,A}` are used to implement different behaviors
for how to promote dimensioned quantities. The concrete subtypes have no fields and
are therefore immutable singletons. Currently implemented subtypes of `Unitful.Units{N,D,A}`
include [`Unitful.FreeUnits{N,D,A}`](@ref), [`Unitful.ContextUnits{N,D,P,A}`](@ref), and
[`Unitful.FixedUnits{N,D,A}`](@ref). Units defined in the Unitful.jl package itself are all
`Unitful.FreeUnits{N,D,A}` objects.

Finally, we define physical quantity types as [`Quantity{T<:Number, D, U}`](@ref), where
`D :: Dimensions` and `U <: Units`. By putting units in the type signature of a
quantity, staged functions can be used to offload as much of the unit
computation to compile-time as is possible. By also having the dimensions
explicitly in the type signature, dispatch can be done on dimensions:
`isa(1u"m", Unitful.Length) == true`. This works because `Length` is a type alias for
some subset of `Unitful.Quantity` subtypes.

## API

### Quantities

```@docs
    Unitful.AbstractQuantity
    Unitful.Quantity
    Unitful.DimensionlessQuantity
```

### Units and dimensions

```@docs
    Unitful.Unitlike
    Unitful.Units
    Unitful.FreeUnits
    Unitful.ContextUnits
    Unitful.FixedUnits
    Unitful.Dimensions
    Unitful.Unit
    Unitful.Dimension
	Unitful.NoDims
```


================================================
FILE: ext/ConstructionBaseUnitfulExt.jl
================================================
module ConstructionBaseUnitfulExt
using Unitful
import ConstructionBase: constructorof

constructorof(::Type{Unitful.Quantity{_,D,U}}) where {_,D,U} =
    Unitful.Quantity{T,D,U} where T

end


================================================
FILE: ext/ForwardDiffExt.jl
================================================
module ForwardDiffExt
using Unitful
using ForwardDiff

function Base.convert(d::Type{ForwardDiff.Dual{T, V, N}}, q::Quantity{T2, NoDims}) where {T, V, N, T2}
    return d(uconvert(NoUnits, q))
end

end


================================================
FILE: ext/InverseFunctionsUnitfulExt.jl
================================================
module InverseFunctionsUnitfulExt
using Unitful
import InverseFunctions: inverse

# `true` plays the role of 1, but doesn't promote unnecessary
inverse(f::Base.Fix1{typeof(ustrip), <:Unitful.Units}) = Base.Fix1(*, true*f.x)

end


================================================
FILE: ext/LatexifyExt.jl
================================================
#=========================================#
# Extension for Unitful.jl + Latexify.jl, #
# based on UnitfulLatexify.jl by          #
# David Gustavsson (@gustaphe)            #
#=========================================#
module LatexifyExt
using Unitful:
    Unitful,
    Unit,
    Units,
    AbstractQuantity,
    AffineUnits,
    AffineQuantity,
    power,
    abbr,
    name,
    tens,
    sortexp,
    unit,
    NoDims,
    ustrip,
    @u_str,
    genericunit,
    has_unit_spacing
using Latexify:
    Latexify,
    @latexrecipe,
    latexify,
    _latexarray,
    latexraw,
    FancyNumberFormatter,
    PlainNumberFormatter,
    StyledNumberFormatter,
    SiunitxNumberFormatter,
    AbstractNumberFormatter
using LaTeXStrings: LaTeXString

import Latexify: latexify

import Base.*

# utility functions ------------------

function get_formatter(kwargs)
    fmt = get(kwargs, :fmt, FancyNumberFormatter())
    if fmt isa String
        fmt = StyledNumberFormatter(fmt)
    end
    return fmt
end
get_format_env(fmt::SiunitxNumberFormatter) = :raw
get_format_env(fmt) = :inline


function getunitname(p::T, unitformat) where {T<:Unit}
    unitname = get(unitnames, (unitformat, name(p)), nothing)
    isnothing(unitname) || return unitname
    if unitformat === :siunitx
        return "\\$(lowercase(String(name(p))))"
    end
    return abbr(p)
end

function listunits(::T) where {T<:Units}
    return sortexp(T.parameters[1])
end

"""
```julia
intersperse(t, delim)
```
Create a vector whose elements alternate between the elements of `t` and `delim`, analogous
to `join` for strings.

# Example
```julia
julia> intersperse((1, 2, 3, 4), :a)
[1, :a, 2, :a, 3, :a, 4]
```
"""
function intersperse(t::T, delim::U) where {T,U}
    iszero(length(t)) && return ()
    L = length(t) * 2 - 1
    out = Vector{Union{typeof.(t)...,U}}(undef, L)
    out[1:2:L] .= t
    out[2:2:L] .= delim
    return out
end

# default ------------------------------

@latexrecipe function f(p::Unit)
    fmt = get_formatter(kwargs)
    env --> get_format_env(fmt)
    return _transform(p, fmt)
end

@latexrecipe function f(u::Units; permode=:power)
    fmt = get_formatter(kwargs)
    env --> get_format_env(fmt)
    return _transform(u, fmt)
end

@latexrecipe function f(q::AbstractQuantity)
    fmt = get_formatter(kwargs)
    env --> get_format_env(fmt)
    operation := :*

    return _transform(q, fmt)
end

struct NakedUnits
    u::Units
end
struct NakedNumber
    n::Number
end

@latexrecipe function f(u::NakedUnits; permode=:power)
    fmt = get_formatter(kwargs)
    unitlist = listunits(u.u)
    if fmt isa SiunitxNumberFormatter
        fmt.simple && return Expr(:latexifymerge, intersperse(unitlist, ".")...)
        return Expr(:latexifymerge, unitlist...)
    end
    if permode === :power
        return Expr(:latexifymerge, intersperse(unitlist, "\\,")...)
    end

    numunits = [x for x in unitlist if power(x) >= 0]
    denunits = [typeof(x)(tens(x), -power(x)) for x in unitlist if power(x) < 0]

    numerator = intersperse(numunits, "\\,")
    if isempty(denunits)
        return Expr(:latexifymerge, numerator...)
    end
    if isempty(numunits)
        numerator = [1]
    end
    denominator = intersperse(denunits, "\\,")

    if permode === :slash
        return Expr(:latexifymerge, numerator..., "\\,/\\,", denominator...)
    end
    if permode === :frac
        return Expr(:latexifymerge, "\\frac{", numerator..., "}{", denominator..., "}")
    end
    return error("permode $permode undefined.")
end

@latexrecipe function f(n::NakedNumber)
    fmt = get_formatter(kwargs)
    if fmt isa SiunitxNumberFormatter
        fmt := PlainNumberFormatter()
    end
    return n.n
end

function _transform(p::Unit, fmt::SiunitxNumberFormatter)
    unitformat = fmt.simple ? :siunitxsimple : :siunitx
    prefix = prefixes[(unitformat, tens(p))]
    pow = power(p)
    unitname = getunitname(p, unitformat)
    if fmt.simple
        per = ""
        expo = pow == 1//1 ? "" : "^{$(latexify(pow; fmt="%g", env=:raw))}"
    else
        per = pow < 0 ? "\\per" : ""
        pow = abs(pow)
        expo = pow == 1//1 ? "" : "\\tothe{$(latexify(pow; fmt="%g", env=:raw))}"
    end
    return LaTeXString("$per$prefix$unitname$expo")
end
function _transform(p::Unit, fmt::AbstractNumberFormatter)
    prefix = prefixes[(:mathrm, tens(p))]
    unitname = getunitname(p, :mathrm)
    pow = power(p)
    expo = pow == 1//1 ? "" : "^{$(latexify(pow; fmt="%g", env=:raw))}"
    return LaTeXString("\\mathrm{$prefix$unitname}$expo")
end

function _transform(u::Units, fmt::SiunitxNumberFormatter)
    opening = fmt.version < 3 ? "\\si{" : "\\unit{"
    return Expr(:latexifymerge, opening, NakedUnits(u), "}")
end
_transform(u::Units, ::AbstractNumberFormatter) = Expr(:latexifymerge, NakedUnits(u))

function _transform(q::AbstractQuantity, fmt::SiunitxNumberFormatter)
    opening = fmt.version < 3 ? "\\SI{" : "\\qty{"
    return Expr(:latexifymerge, opening, NakedNumber(q.val), "}{", NakedUnits(unit(q)), "}")
end
function _transform(q::AbstractQuantity, ::AbstractNumberFormatter)
    Expr(
        :latexifymerge,
        NakedNumber(q.val),
        has_unit_spacing(unit(q)) ? "\\," : nothing,
        NakedUnits(unit(q)),
    )
end
_transform(n::NakedNumber, ::SiunitxNumberFormatter) = PlainNumberFormatter(n.n)


# affine -------------------------------

@latexrecipe function f(u::AffineUnits)
    fmt = get_formatter(kwargs)
    if u == Unitful.°C
        unitname = :Celsius
    elseif u == Unitful.°F
        unitname = :Fahrenheit
    else
        # If it's not celsius or farenheit, let it do the default thing
        return genericunit(u)
    end
    if fmt isa SiunitxNumberFormatter
        env --> :raw
        return Expr(:latexifymerge, "\\unit{", unitnames[(:siunitx, unitname)], "}")
    end
    env --> :inline
    return Expr(:latexifymerge, "\\mathrm{", unitnames[(:mathrm, unitname)], "}")
end

@latexrecipe function f(q::AffineQuantity)
    fmt = get_formatter(kwargs)
    u = unit(q)
    if u == Unitful.°C
        unitname = :Celsius
    elseif u == Unitful.°F
        unitname = :Fahrenheit
    else
        # If it's not celsius or farenheit, let it do the default thing
        return ustrip(q)*genericunit(u)
    end
    if fmt isa SiunitxNumberFormatter
        env --> :raw
        return Expr(
            :latexifymerge,
            "\\qty{",
            NakedNumber(q.val),
            "}{",
            unitnames[(:siunitx, unitname)],
            "}",
        )
    end
    env --> :inline
    return Expr(:latexifymerge, q.val, "\\,\\mathrm{", unitnames[(:mathrm, unitname)], "}")
end

# arrays ------------------------- 
@latexrecipe function f( # Array{Quantity{U}}
    a::AbstractArray{<:AbstractQuantity{N,D,U}};
) where {N<:Number,D,U}
    # Array of quantities with the same unit
    env --> :equation
    return Expr(
        :latexifymerge, ustrip.(a), has_unit_spacing(first(a)) ? "\\," : "", unit(first(a))
    )
end

@latexrecipe function f( # Tuple{Quantity{U}}
    l::Tuple{T,Vararg{T}},
) where {T<:AbstractQuantity{N,D,U}} where {N<:Number,D,U}
    fmt = get_formatter(kwargs)
    if fmt isa SiunitxNumberFormatter
        env --> :raw
        opening = fmt.version < 3 ? "\\SIlist{" : "\\qtylist{"
        return Expr(
            :latexifymerge,
            opening,
            intersperse(NakedNumber.(ustrip.(l)), ";")...,
            "}{",
            NakedUnits(unit(first(l))),
            "}",
        )
    end
    return collect(l)
end

# label (for plots) ------------------------------------

@latexrecipe function f(l::AbstractString, u::Units; labelformat=:slash)
    labelformat === :slash && return Expr(:latexifymerge, l, "\\;\\left/\\;", u, "\\right.")
    labelformat === :square && return Expr(:latexifymerge, l, "\\;\\left[", u, "\\right]")
    labelformat === :round && return Expr(:latexifymerge, l, "\\;\\left(", u, "\\right)")
    labelformat === :frac && return Expr(:latexifymerge, "\\frac{", l, "}{", u, "}")
    error("Unknown labelformat $labelformat")
end

# prefixes ------------------------------

"""
prefixes are listed in this dictionary
`(unitformat::Symbol, pow::Integer) => prefix::String`
"""
const prefixes = begin
    Dict(
        (:mathrm, -24) => "y",
        (:mathrm, -21) => "z",
        (:mathrm, -18) => "a",
        (:mathrm, -15) => "f",
        (:mathrm, -12) => "p",
        (:mathrm, -9) => "n",
        (:mathrm, -6) => "\\mu{}",
        (:mathrm, -3) => "m",
        (:mathrm, -2) => "c",
        (:mathrm, -1) => "d",
        (:mathrm, 0) => "",
        (:mathrm, 1) => "D",
        (:mathrm, 2) => "h",
        (:mathrm, 3) => "k",
        (:mathrm, 6) => "M",
        (:mathrm, 9) => "G",
        (:mathrm, 12) => "T",
        (:mathrm, 15) => "P",
        (:mathrm, 18) => "E",
        (:mathrm, 21) => "Z",
        (:mathrm, 24) => "Y",
        (:siunitx, -24) => "\\yocto",
        (:siunitx, -21) => "\\zepto",
        (:siunitx, -18) => "\\atto",
        (:siunitx, -15) => "\\femto",
        (:siunitx, -12) => "\\pico",
        (:siunitx, -9) => "\\nano",
        (:siunitx, -6) => "\\micro",
        (:siunitx, -3) => "\\milli",
        (:siunitx, -2) => "\\centi",
        (:siunitx, -1) => "\\deci",
        (:siunitx, 0) => "",
        (:siunitx, 1) => "\\deka",
        (:siunitx, 2) => "\\hecto",
        (:siunitx, 3) => "\\kilo",
        (:siunitx, 6) => "\\mega",
        (:siunitx, 9) => "\\giga",
        (:siunitx, 12) => "\\tera",
        (:siunitx, 15) => "\\peta",
        (:siunitx, 18) => "\\exa",
        (:siunitx, 21) => "\\zetta",
        (:siunitx, 24) => "\\yotta",
        (:siunitxsimple, -24) => "y",
        (:siunitxsimple, -21) => "z",
        (:siunitxsimple, -18) => "a",
        (:siunitxsimple, -15) => "f",
        (:siunitxsimple, -12) => "p",
        (:siunitxsimple, -9) => "n",
        (:siunitxsimple, -6) => "\\u",
        (:siunitxsimple, -3) => "m",
        (:siunitxsimple, -2) => "c",
        (:siunitxsimple, -1) => "d",
        (:siunitxsimple, 0) => "",
        (:siunitxsimple, 1) => "D",
        (:siunitxsimple, 2) => "h",
        (:siunitxsimple, 3) => "k",
        (:siunitxsimple, 6) => "M",
        (:siunitxsimple, 9) => "G",
        (:siunitxsimple, 12) => "T",
        (:siunitxsimple, 15) => "P",
        (:siunitxsimple, 18) => "E",
        (:siunitxsimple, 21) => "Z",
        (:siunitxsimple, 24) => "Y",
    )
end

# unit names ------------------------------

""""
`unitnames`

Unit names generally follow a simple scheme, but there are exceptions, listed in this
dictionary: `(unitformat::Symbol, name::Symbol) => unitname::String`
"""
const unitnames = begin
    Dict(
        (:mathrm, :Percent) => "\\%",
        (:siunitxsimple, :Percent) => "\\%",
        (:mathrm, :Degree) => "^{\\circ}",
        (:siunitxsimple, :Degree) => "\\degree",
        (:siunitx, :eV) => "\\electronvolt",
        (:mathrm, :Ohm) => "\\Omega",
        (:mathrm, :Celsius) => "^\\circ C",
        (:siunitx, :Celsius) => "\\celsius",
        (:siunitxsimple, :Celsius) => "\\celsius",
        (:mathrm, :Fahrenheit) => "^\\circ F",
        (:siunitx, :Fahrenheit) => "\\fahrenheit",
        (:siunitxsimple, :Fahrenheit) => "\\fahrenheit",
        (:siunitxsimple, :Angstrom) => "\\angstrom",
        (:mathrm, :Angstrom) => "\\AA",
        (:mathrm, :DoubleTurn) => "\\S",
        (:mathrm, :Turn) => "\\tau",
        (:mathrm, :HalfTurn) => "\\pi",
        (:mathrm, :Quadrant) => "\\frac{\\pi}{2}",
        (:mathrm, :Sextant) => "\\frac{\\pi}{3}",
        (:mathrm, :Octant) => "\\frac{\\pi}{4}",
        (:mathrm, :ClockPosition) => "\\frac{\\pi}{12}",
        (:mathrm, :HourAngle) => "\\frac{\\pi}{24}",
        (:mathrm, :CompassPoint) => "\\frac{\\pi}{32}",
        (:mathrm, :Hexacontade) => "\\frac{\\pi}{60}",
        (:mathrm, :BinaryRadian) => "\\frac{\\pi}{256}",
        (:mathrm, :DiameterPart) => "\\oslash", # This is slightly wrong
        (:mathrm, :Gradian) => "^g",
        (:mathrm, :Arcminute) => "'",
        (:mathrm, :Arcsecond) => "''",
        (:mathrm, :ArcsecondShort) => "''",
    )
end

end # LatexifyExt

================================================
FILE: ext/NaNMathExt.jl
================================================
module NaNMathExt
using Unitful
import NaNMath

NaNMath.sqrt(q::Unitful.AbstractQuantity) = NaNMath.sqrt(ustrip(q))*sqrt(unit(q))
NaNMath.pow(q::Unitful.AbstractQuantity, r) = NaNMath.pow(ustrip(q), r)*unit(q)^r
end


================================================
FILE: ext/PrintfExt.jl
================================================
module PrintfExt

using Printf
using Unitful
using Unitful: AbstractQuantity

Printf.plength(f::Printf.Spec{<:Printf.Ints}, x::AbstractQuantity{<:Real}) = Printf.plength(f, ustrip(x)) + length(string(unit(x))) + Unitful.has_unit_spacing(unit(x))

# separate methods for disambiguation
Printf.fmt(buf, pos, arg::AbstractQuantity{<:Real}, spec::Printf.Spec{<:Printf.Floats}) = _fmt(buf, pos, arg, spec)
Printf.fmt(buf, pos, arg::AbstractQuantity{<:Real}, spec::Printf.Spec{<:Printf.Ints}) = _fmt(buf, pos, arg, spec)

function _fmt(buf, pos, arg, spec)
    pos = Printf.fmt(buf, pos, ustrip(arg), spec)
    if Unitful.has_unit_spacing(unit(arg))
        pos = Printf.fmt(buf, pos, ' ', only((Printf.format"%c").formats))
    end
    pos = Printf.fmt(buf, pos, string(unit(arg)), only((Printf.format"%s").formats))
    return pos
end

end


================================================
FILE: src/Unitful.jl
================================================
module Unitful

import Base: ==, <, <=, +, -, *, /, //, ^, isequal, hash
import Base: show, convert
import Base: abs, abs2, angle, big, float, fma, muladd, inv, sqrt, cbrt
import Base: min, max, floor, ceil, real, imag, conj
import Base: complex, widen, reim # handled in complex.jl
import Base: exp, exp10, exp2, expm1, log, log10, log1p, log2
import Base: sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh,
             sinpi, cospi, sinc, cosc, cis, cispi, sincos
import Base: eps, mod, rem, div, fld, cld, divrem, trunc, round, sign, signbit
import Base: isless, isapprox, isinteger, isreal, isinf, isfinite, isnan
import Base: iseven, isodd
import Base: copysign, flipsign
import Base: prevfloat, nextfloat, maxintfloat, rat, step
import Base: length, float, last, one, oneunit, zero, range
import Base: getindex, eltype, step, last, first, frexp
import Base: Integer, Rational, typemin, typemax
import Base: steprange_last, unsigned
import Base: sleep
@static if VERSION ≥ v"1.7.0-DEV.119"
    import Base: isunordered
end

import Dates
import LinearAlgebra: Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal
import LinearAlgebra: istril, istriu, norm
import Random

export logunit, unit, absoluteunit, dimension, uconvert, ustrip, upreferred
export @dimension, @derived_dimension, @refunit, @unit, @affineunit, @u_str
export Quantity, DimensionlessQuantity, NoUnits, NoDims

export uconvertp, uconvertrp, reflevel, linear
export @logscale, @logunit, @dB, @B, @cNp, @Np
export Level, Gain
export uparse

const unitmodules = Vector{Module}()

function _basefactors(m::Module)
    # A hidden symbol which will be automatically attached to any module
    # defining units, allowing `Unitful.register()` to merge in the units from
    # that module.
    basefactors_name = Symbol("#Unitful_basefactors")
    if isdefined(m, basefactors_name)
        # It's not guaranteed that a world age update happened since the hidden
        # symbol was added to another module, so use `invokelatest` to avoid #781.
        Base.invokelatest(getproperty, m, basefactors_name)
    else
        Core.eval(m, :(const $basefactors_name = Dict{Symbol,Tuple{Float64,Rational{Int}}}()))
    end
end

const basefactors = _basefactors(Unitful)

include("types.jl")
const promotion = Dict{Symbol,FreeUnits}()

include("user.jl")
include("utils.jl")
include("dimensions.jl")
include("units.jl")
include("quantities.jl")
include("display.jl")
include("promotion.jl")
include("conversion.jl")
include("range.jl")
include("fastmath.jl")
include("logarithm.jl")
include("complex.jl")
include("pkgdefaults.jl")
include("dates.jl")

if !isdefined(Base, :get_extension)
    include("../ext/ConstructionBaseUnitfulExt.jl")
    include("../ext/InverseFunctionsUnitfulExt.jl")
end

end


================================================
FILE: src/complex.jl
================================================
# This file is meant to provide all the methods in
# https://github.com/JuliaLang/julia/blob/master/base/complex.jl that
# are defined for Real or Complex numbers, just for
# AbstractQuantities{T,D,U} where T is Real or Complex, respectively.
#
# It is currently incomplete.

complex(z::Quantity{T,D,U}) where {T<:Complex,D,U} = z
function complex(x::Quantity{T}, y = zero(x)) where {T<:Real}
    r, i = promote(x, y)
    return Quantity(complex(ustrip(r), ustrip(i)), unit(r))
end
complex(::Type{Quantity{T,D,U}}) where {T,D,U} =
    Quantity{complex(T),D,U}

# implement Base.widen for real and complex quantities because Unitful
# does not have an implementation for widen yet
Base.widen(::Type{Quantity{T,D,U}}) where {T,D,U} =
    Quantity{widen(T),D,U}

# skip Base.float, Base.real, Base.imag because it is already
# implemented

# Base.real for types has a general implementation in julia; a faster
# method could be provided but is not strictly required.

# Base.isreal, etc., are already implemented in Unitful.

# Base.flipsign is already implemented in Unitful.

# To Do: Check if Base.show, Base.read, Base.write, etc. need any
#        attention

# ...


================================================
FILE: src/conversion.jl
================================================
"""
    convfact(s::Units, t::Units)
Find the conversion factor from unit `t` to unit `s`, e.g., `convfact(m, cm) == 1//100`.
"""
@generated function convfact(s::Units, t::Units)
    # Check if conversion is possible in principle
    dimension(s()) != dimension(t()) && throw(DimensionError(s(), t()))

    # use absoluteunit because division is invalid for AffineUnits;
    # convert to FreeUnits first because absolute ContextUnits might still
    # promote to AffineUnits
    conv_units = absoluteunit(FreeUnits(t())) / absoluteunit(FreeUnits(s()))
    inex, ex = basefactor(conv_units)
    pow = tensfactor(conv_units)
    inex_orig = inex

    fpow = 10.0^pow
    if fpow > typemax(Int) || 1/fpow > typemax(Int)
        inex *= fpow
    else
        comp = (pow > 0 ? fpow * numerator(ex) : 1/fpow * denominator(ex))
        if comp > typemax(Int)
            inex *= fpow
        else
            ex *= (10//1)^pow
        end
    end

    if ex isa Rational && denominator(ex) == 1
        ex = numerator(ex)
    end

    result = (inex ≈ 1.0 ? 1 : inex) * ex
    if fp_overflow_underflow(inex_orig, result)
        throw(ArgumentError(
            "Floating point overflow/underflow, probably due to large " *
            "exponents and/or SI prefixes in units"
        ))
    end
    return :($result)
end

"""
    convfact{S}(s::Units{S}, t::Units{S})
Returns 1. (Avoids effort when unnecessary.)
"""
convfact(s::Units{S}, t::Units{S}) where {S} = 1

"""
    convfact(T::Type, s::Units, t::Units)
Returns the appropriate conversion factor from unit `t` to unit `s` for the number type `T`.
"""
function convfact(::Type{T}, s::Units, t::Units) where T
    cf = convfact(s, t)
    if cf isa AbstractFloat
        F = convfact_floattype(T)
        # Since conversion factors only have Float64 precision,
        # there is no point in converting to BigFloat
        convert(F == BigFloat ? Float64 : F, cf)
    else
        cf
    end
end

function convfact_floattype(::Type{T}) where T
    # Use try-catch instead of hasmethod because a
    # fallback method might exist but throw an error
    try
        _convfact_floattype(float(real(T)))
    catch
        Float64
    end
end

_convfact_floattype(::Type) = Float64
_convfact_floattype(::Type{Float16}) = Float16
_convfact_floattype(::Type{Float32}) = Float32

"""
    uconvert(a::Units, x::Quantity{T,D,U}) where {T,D,U}
Convert a [`Unitful.Quantity`](@ref) to different units. The conversion will
fail if the target units `a` have a different dimension than the dimension of
the quantity `x`. You can use this method to switch between equivalent
representations of the same unit, like `N m` and `J`.

Example:

```jldoctest
julia> uconvert(u"hr",3602u"s")
1801//1800 hr

julia> uconvert(u"J",1.0u"N*m")
1.0 J
```
"""
function uconvert(a::Units, x::Quantity{T,D,U}) where {T,D,U}
    if typeof(a) == U
        return Quantity(x.val, a)    # preserves numeric type if convfact is 1
    elseif (a isa AffineUnits) || (x isa AffineQuantity)
        return uconvert_affine(a, x)
    else
        return Quantity(x.val * convfact(T, a, U()), a)
    end
end

function uconvert(a::Units, x::Number)
    if dimension(a) == NoDims
        Quantity(x * convfact(a, NoUnits), a)
    else
        throw(DimensionError(a,x))
    end
end

uconvert(a::Units, x::Missing) = missing

@generated function uconvert_affine(a::Units, x::Quantity)
    # TODO: test, may be able to get bad things to happen here when T<:LogScaled
    auobj = a()
    xuobj = x.parameters[3]()
    conv = convfact(auobj, xuobj)

    t0 = x <: AffineQuantity ? x.parameters[3].parameters[end].parameters[end] :
        :(zero($(x.parameters[1])))
    t1 = a <: AffineUnits ? a.parameters[end].parameters[end] :
        :(zero($(x.parameters[1])))
    quote
        dimension(a) != dimension(x) && throw(DimensionError(a, x))
        return Quantity(((x.val - $t0) * $conv) + $t1, a)
    end
end

function convert(::Type{Quantity{T,D,U}}, x::Number) where {T,D,U}
    (dimension(x) != D) && throw(DimensionError(U(), x))
    q = uconvert(U(), x)
    Quantity{T,D,U}(isa(q, AbstractQuantity) ? q.val : q)
end

# needed ever since julialang/julia#28216
convert(::Type{Quantity{T,D,U}}, x::Quantity{T,D,U}) where {T,D,U} = x

function convert(::Type{Quantity{T,D}}, x::Quantity) where {T,D}
    (dimension(x) !== D) && throw(DimensionError(D, x))
    return Quantity{T,D,typeof(unit(x))}(convert(T, x.val))
end
function convert(::Type{Quantity{T,D}}, x::Number) where {T,D}
    (D !== NoDims) && throw(DimensionError(D, NoDims))
    Quantity{T,NoDims,typeof(NoUnits)}(x)
end
function convert(::Type{Quantity{T}}, x::Quantity) where {T}
    Quantity{T,dimension(x),typeof(unit(x))}(convert(T, x.val))
end
function convert(::Type{Quantity{T}}, x::Number) where {T}
    Quantity{T,NoDims,typeof(NoUnits)}(x)
end

convert(::Type{DimensionlessQuantity{T,U}}, x::Number) where {T,U} =
    uconvert(U(), convert(T,x))
function convert(::Type{DimensionlessQuantity{T,U}}, x::Quantity) where {T,U}
    if dimension(x) == NoDims
        _Quantity(T(x.val), U())
    else
        throw(DimensionError(NoDims,x))
    end
end

convert(::Type{Number}, y::Quantity) = y
convert(::Type{T}, y::Quantity) where {T <: Real} =
    T(uconvert(NoUnits, y))
convert(::Type{T}, y::Quantity) where {T <: Complex} =
    T(uconvert(NoUnits, y))


================================================
FILE: src/dates.jl
================================================
# Conversion from and to types from the `Dates` stdlib

# Dates.FixedPeriod

for (period, unit) = ((Dates.Week, wk), (Dates.Day, d), (Dates.Hour, hr),
                      (Dates.Minute, minute), (Dates.Second, s), (Dates.Millisecond, ms),
                      (Dates.Microsecond, μs), (Dates.Nanosecond, ns))
    @eval unit(::Type{$period}) = $unit
    @eval (::Type{$period})(x::AbstractQuantity) = $period(ustrip(unit($period), x))
end

dimension(p::Dates.FixedPeriod) = dimension(typeof(p))
dimension(::Type{<:Dates.FixedPeriod}) = 𝐓

"""
    unit(x::Dates.FixedPeriod)
    unit(x::Type{<:Dates.FixedPeriod})

Return the units that correspond to a particular period.

# Examples

```jldoctest
julia> using Dates

julia> unit(Second(15)) == u"s"
true

julia> unit(Hour) == u"hr"
true
```
"""
unit(p::Dates.FixedPeriod) = unit(typeof(p))

numtype(x::Dates.FixedPeriod) = numtype(typeof(x))
numtype(::Type{T}) where {T<:Dates.FixedPeriod} = Int64

quantitytype(::Type{T}) where {T<:Dates.FixedPeriod} =
    Quantity{numtype(T),dimension(T),typeof(unit(T))}

ustrip(p::Dates.FixedPeriod) = Dates.value(p)

"""
    Quantity(period::Dates.FixedPeriod)

Create a `Quantity` that corresponds to the given `period`. The numerical value of the
resulting `Quantity` is of type `Int64`.

# Example

```jldoctest
julia> using Dates: Second

julia> Quantity(Second(5))
5 s
```
"""
Quantity(period::Dates.FixedPeriod) = Quantity(ustrip(period), unit(period))

uconvert(u::Units, period::Dates.FixedPeriod) = uconvert(u, Quantity(period))

(T::Type{<:AbstractQuantity})(period::Dates.FixedPeriod) = T(Quantity(period))

convert(T::Type{<:AbstractQuantity}, period::Dates.FixedPeriod) = T(period)
convert(T::Type{<:Dates.FixedPeriod}, x::AbstractQuantity) = T(x)

round(T::Type{<:Dates.FixedPeriod}, x::AbstractQuantity, r::RoundingMode=RoundNearest) =
    T(round(numtype(T), ustrip(unit(T), x), r))
round(u::Units, period::Dates.FixedPeriod, r::RoundingMode=RoundNearest; kwargs...) =
    round(u, Quantity(period), r; kwargs...)
round(T::Type{<:Number}, u::Units, period::Dates.FixedPeriod, r::RoundingMode=RoundNearest;
      kwargs...) = round(T, u, Quantity(period), r; kwargs...)
round(T::Type{<:AbstractQuantity}, period::Dates.FixedPeriod, r::RoundingMode=RoundNearest;
      kwargs...) = round(T, Quantity(period), r; kwargs...)

for (f, r) in ((:floor,:RoundDown), (:ceil,:RoundUp), (:trunc,:RoundToZero))
    @eval $f(T::Type{<:Dates.FixedPeriod}, x::AbstractQuantity) = round(T, x, $r)
    @eval $f(u::Units, period::Dates.FixedPeriod; kwargs...) =
        round(u, period, $r; kwargs...)
    @eval $f(T::Type{<:Number}, u::Units, period::Dates.FixedPeriod; kwargs...) =
        round(T, u, period, $r; kwargs...)
    @eval $f(T::Type{<:AbstractQuantity}, period::Dates.FixedPeriod; kwargs...) =
        round(T, period, $r; kwargs...)
end

for op = (:+, :-, :*, :/, ://, :fld, :cld, :mod, :rem, :atan,
          :(==), :isequal, :<, :isless, :≤)
    @eval $op(x::Dates.FixedPeriod, y::AbstractQuantity) = $op(Quantity(x), y)
    @eval $op(x::AbstractQuantity, y::Dates.FixedPeriod) = $op(x, Quantity(y))
end
for op = (:*, :/, ://)
    @eval $op(x::Dates.FixedPeriod, y::Units) = $op(Quantity(x), y)
    @eval $op(x::Units, y::Dates.FixedPeriod) = $op(x, Quantity(y))
end
div(x::Dates.FixedPeriod, y::AbstractQuantity, r...) = div(Quantity(x), y, r...)
div(x::AbstractQuantity, y::Dates.FixedPeriod, r...) = div(x, Quantity(y), r...)

isapprox(x::Dates.FixedPeriod, y::AbstractQuantity; kwargs...) =
    isapprox(Quantity(x), y; kwargs...)
isapprox(x::AbstractQuantity, y::Dates.FixedPeriod; kwargs...) =
    isapprox(x, Quantity(y); kwargs...)

function isapprox(x::AbstractArray{<:AbstractQuantity}, y::AbstractArray{T};
                  kwargs...) where {T<:Dates.Period}
    if isconcretetype(T)
        y′ = reinterpret(quantitytype(T), y)
    else
        y′ = Quantity.(y)
    end
    isapprox(x, y′; kwargs...)
end
isapprox(x::AbstractArray{<:Dates.FixedPeriod}, y::AbstractArray{<:AbstractQuantity};
         kwargs...) = isapprox(y, x; kwargs...)

Base.promote_rule(::Type{Quantity{T,𝐓,U}}, ::Type{S}) where {T,U,S<:Dates.FixedPeriod} =
    promote_type(Quantity{T,𝐓,U}, quantitytype(S))

# Dates.CompoundPeriod

dimension(p::Dates.CompoundPeriod) = dimension(typeof(p))
dimension(::Type{<:Dates.CompoundPeriod}) = 𝐓

uconvert(u::Units, period::Dates.CompoundPeriod) =
    Quantity{promote_type(Int64,typeof(convfact(u,ns))),dimension(u),typeof(u)}(period)

try_uconvert(u::Units, period::Dates.CompoundPeriod) = nothing
function try_uconvert(u::TimeUnits, period::Dates.CompoundPeriod)
    T = Quantity{promote_type(Int64,typeof(convfact(u,ns))),dimension(u),typeof(u)}
    val = zero(T)
    for p in period.periods
        p isa Dates.FixedPeriod || return nothing
        val += T(p)
    end
    val
end

(T::Type{<:AbstractQuantity})(period::Dates.CompoundPeriod) =
    mapreduce(T, +, period.periods, init=zero(T))

convert(T::Type{<:AbstractQuantity}, period::Dates.CompoundPeriod) = T(period)

round(u::Units, period::Dates.CompoundPeriod, r::RoundingMode=RoundNearest; kwargs...) =
    round(u, uconvert(u, period), r; kwargs...)
round(T::Type{<:Number}, u::Units, period::Dates.CompoundPeriod,
      r::RoundingMode=RoundNearest; kwargs...) =
    round(T, u, uconvert(u, period), r; kwargs...)
round(T::Type{<:AbstractQuantity}, period::Dates.CompoundPeriod,
      r::RoundingMode=RoundNearest; kwargs...) =
    round(T, T(period), r; kwargs...)

for (f, r) in ((:floor,:RoundDown), (:ceil,:RoundUp), (:trunc,:RoundToZero))
    @eval $f(u::Units, period::Dates.CompoundPeriod; kwargs...) =
        round(u, period, $r; kwargs...)
    @eval $f(T::Type{<:Number}, u::Units, period::Dates.CompoundPeriod; kwargs...) =
        round(T, u, period, $r; kwargs...)
    @eval $f(T::Type{<:AbstractQuantity}, period::Dates.CompoundPeriod; kwargs...) =
        round(T, period, $r; kwargs...)
end

for op = (:fld, :cld, :atan, :<, :isless, :≤)
    @eval $op(x::Dates.CompoundPeriod, y::AbstractQuantity) = $op(uconvert(unit(y),x), y)
    @eval $op(x::AbstractQuantity, y::Dates.CompoundPeriod) = $op(x, uconvert(unit(x),y))
end
div(x::Dates.CompoundPeriod, y::AbstractQuantity, r...) = div(uconvert(unit(y),x), y, r...)
div(x::AbstractQuantity, y::Dates.CompoundPeriod, r...) = div(x, uconvert(unit(x),y), r...)
mod(x::Dates.CompoundPeriod, y::AbstractQuantity) = mod(uconvert(unit(y),x), y)
rem(x::Dates.CompoundPeriod, y::AbstractQuantity) = rem(uconvert(unit(y),x), y)
for op = (:(==), :isequal)
    @eval $op(x::Dates.CompoundPeriod, y::AbstractQuantity{T,𝐓,U}) where {T,U} =
        $op(try_uconvert(U(), x), y)
    @eval $op(x::AbstractQuantity{T,𝐓,U}, y::Dates.CompoundPeriod) where {T,U} =
        $op(x, try_uconvert(U(), y))
end

isapprox(x::Dates.CompoundPeriod, y::AbstractQuantity; kwargs...) =
    dimension(y) === 𝐓 ? isapprox(uconvert(unit(y), x), y; kwargs...) : false
isapprox(x::AbstractQuantity, y::Dates.CompoundPeriod; kwargs...) =
    dimension(x) === 𝐓 ? isapprox(x, uconvert(unit(x), y); kwargs...) : false

function isapprox(x::AbstractArray{<:AbstractQuantity},
                  y::AbstractArray{Dates.CompoundPeriod}; kwargs...)
    if dimension(eltype(x)) === 𝐓
        isapprox(x, uconvert.(unit(eltype(x)), y); kwargs...)
    else
        false
    end
end

isapprox(x::AbstractArray{Dates.CompoundPeriod}, y::AbstractArray{<:AbstractQuantity};
         kwargs...) = isapprox(y, x; kwargs...)

sleep(x::AbstractQuantity) = sleep(ustrip(s, x))

# Dates, Times, DateTimes

for f in (:+, :-)
    @eval Base.$f(x::Dates.DateTime, y::Quantity) = $f(x, trunc(Dates.Millisecond, y))
    @eval Base.$f(x::Dates.Time, y::Quantity) = $f(x, trunc(Dates.Nanosecond, y))
    @eval Base.$f(x::Dates.Date, y::Quantity) = $f(x, Dates.Day(y))
end
Base.:+(y::Quantity, x::Dates.DateTime) = x + y
Base.:+(y::Quantity, x::Dates.Time) = x + y
Base.:+(y::Quantity, x::Dates.Date) = x + y


================================================
FILE: src/dimensions.jl
================================================
"""
```
*(a0::Dimensions, a::Dimensions...)
```

Given however many dimensions, multiply them together.

Collect [`Unitful.Dimension`](@ref) objects from the type parameter of the
[`Unitful.Dimensions`](@ref) objects. For identical dimensions, collect powers
and sort uniquely by the name of the `Dimension`.

Examples:

```jldoctest
julia> u"𝐌*𝐋/𝐓^2"
𝐋 𝐌 𝐓^-2

julia> u"𝐋*𝐌/𝐓^2"
𝐋 𝐌 𝐓^-2

julia> typeof(u"𝐋*𝐌/𝐓^2") == typeof(u"𝐌*𝐋/𝐓^2")
true
```
"""
@generated function *(a0::Dimensions, a::Dimensions...)
    # Implementation is very similar to *(::Units, ::Units...)
    b = Vector{Dimension}()
    a0p = a0.parameters[1]
    length(a0p) > 0 && append!(b, a0p)
    for x in a
        xp = x.parameters[1]
        length(xp) > 0 && append!(b, xp)
    end

    sort!(b, by=power)
    sort!(b, by=name)

    c = Vector{Dimension}()
    if !isempty(b)
        next = iterate(b)
        p = 0//1
        oldvalue = next[1]
        while next !== nothing
            (value, state) = next
            if name(value) == name(oldvalue)
                p += power(value)
            else
                if p != 0
                    push!(c, Dimension{name(oldvalue)}(p))
                end
                p = power(value)
            end
            oldvalue = value
            next = iterate(b, state)
        end

        if p != 0
            push!(c, Dimension{name(oldvalue)}(p))
        end
    end

    d = (c...,)
    :(Dimensions{$d}())
end

/(x::Dimensions, y::Dimensions) = *(x,inv(y))
//(x::Dimensions, y::Dimensions)  = x/y

# Both methods needed for ambiguity resolution
^(x::Dimension{T}, y::Integer) where {T} = Dimension{T}(power(x)*y)
^(x::Dimension{T}, y::Number) where {T} = Dimension{T}(power(x)*y)

# A word of caution:
# Exponentiation is not type-stable for `Dimensions` objects in many cases
^(x::Dimensions{T}, y::Integer) where {T} = *(Dimensions{map(a->a^y, T)}())
^(x::Dimensions{T}, y::Number) where {T} = *(Dimensions{map(a->a^y, T)}())

@generated function Base.literal_pow(::typeof(^), x::Dimensions{T}, ::Val{p}) where {T,p}
    z = *(Dimensions{map(a->a^p, T)}())
    :($z)
end

# Since exponentiation is not type stable, we define a special `inv` method to enable fast
# division. For julia 0.6.0, the appropriate methods for ^ and * need to be defined before
# this one!
for (fun,pow) in ((:inv, -1//1), (:sqrt, 1//2), (:cbrt, 1//3))
    # The following are generated functions to ensure type stability.
    @eval @generated function ($fun)(x::Dimensions)
        dimtuple = map(x->x^($pow), x.parameters[1])
        y = *(Dimensions{dimtuple}())    # sort appropriately
        :($y)
    end
end


================================================
FILE: src/display.jl
================================================
# Convenient dictionary for mapping powers of ten to an SI prefix.
const prefixdict = Dict(
    -24 => "y",
    -21 => "z",
    -18 => "a",
    -15 => "f",
    -12 => "p",
    -9  => "n",
    -6  => "μ",
    -3  => "m",
    -2  => "c",
    -1  => "d",
    0   => "",
    1   => "da",
    2   => "h",
    3   => "k",
    6   => "M",
    9   => "G",
    12  => "T",
    15  => "P",
    18  => "E",
    21  => "Z",
    24  => "Y"
)

"""
    abbr(x)
Provides abbreviations for units or dimensions. Since a method should
always be defined for each unit and dimension type, absence of a method for a
specific unit or dimension type is likely an error. Consequently, we return ❓
for generic arguments to flag unexpected behavior.
"""
abbr(x) = "❓"     # Indicate missing abbreviations

"""
    prefix(x::Unit)
Returns a string representing the SI prefix for the power-of-ten held by
this particular unit.
"""
function prefix(x::Unit)
    if haskey(prefixdict, tens(x))
        return prefixdict[tens(x)]
    else
        error("Invalid power-of-ten prefix.")
    end
end

function show(io::IO, x::Unit{N,D}) where {N,D}
    show(io, FreeUnits{(x,), D, nothing}())
end

abstract type BracketStyle end

struct NoBrackets <: BracketStyle end
print_opening_bracket(io::IO, ::NoBrackets) = nothing
print_closing_bracket(io::IO, ::NoBrackets) = nothing

struct RoundBrackets <: BracketStyle end
print_opening_bracket(io::IO, ::RoundBrackets) = print(io, '(')
print_closing_bracket(io::IO, ::RoundBrackets) = print(io, ')')

struct SquareBrackets <: BracketStyle end
print_opening_bracket(io::IO, ::SquareBrackets) = print(io, '[')
print_closing_bracket(io::IO, ::SquareBrackets) = print(io, ']')

print_opening_bracket(io::IO, x) = print_opening_bracket(io, BracketStyle(x))
print_closing_bracket(io::IO, x) = print_closing_bracket(io, BracketStyle(x))

"""
    BracketStyle(x)
    BracketStyle(typeof(x))

`BracketStyle` specifies whether the numeric value of a `Quantity` is printed in brackets
(and what kind of brackets). Three styles are defined:

* `NoBrackets()`: this is the default, for example used for real numbers: `1.2 m`
* `RoundBrackets()`: used for complex numbers: `(2.5 + 1.0im) V`
* `SquareBrackets()`: used for [`Level`](@ref)/[`Gain`](@ref): `[3 dB] Hz^-1`
"""
BracketStyle(x) = BracketStyle(typeof(x))
BracketStyle(::Type) = NoBrackets()
BracketStyle(::Type{<:Complex}) = RoundBrackets()

"""
    showval(io::IO, x::Number, brackets::Bool=true)

Show the numeric value `x` of a quantity. Depending on the type of `x`, the value may be
enclosed in brackets (see [`BracketStyle`](@ref)). If `brackets` is set to `false`, the
brackets are not printed.
"""
function showval(io::IO, x::Number, brackets::Bool=true)
    brackets && print_opening_bracket(io, x)
    show(io, x)
    brackets && print_closing_bracket(io, x)
end

function showval(io::IO, mime::MIME, x::Number, brackets::Bool=true)
    brackets && print_opening_bracket(io, x)
    show(io, mime, x)
    brackets && print_closing_bracket(io, x)
end

# Space between numerical value and unit should always be included
# except for angular degrees, minutes and seconds (° ′ ″)
# See SI 9th edition, section 5.4.3; "Formatting the value of a quantity"
# https://www.bipm.org/utils/common/pdf/si-brochure/SI-Brochure-9.pdf
has_unit_spacing(u) = true
has_unit_spacing(u::Units{(Unit{:Degree, NoDims}(0, 1//1),), NoDims}) = false

"""
    show(io::IO, x::Quantity)
Show a unitful quantity by calling [`showval`](@ref) on the numeric value, appending a
space, and then calling `show` on a units object `U()`.
"""
function show(io::IO, x::Quantity)
    if isunitless(unit(x))
        showval(io, x.val, false)
    else
        showval(io, x.val, true)
        has_unit_spacing(unit(x)) && print(io, ' ')
        show(io, unit(x))
    end
end

function show(io::IO, mime::MIME"text/plain", x::Quantity)
    if isunitless(unit(x))
        showval(io, mime, x.val, false)
    else
        showval(io, mime, x.val, true)
        has_unit_spacing(unit(x)) && print(io, ' ')
        show(io, mime, unit(x))
    end
end

function show(io::IO, r::StepRange{T}) where T<:Quantity
    a,s,b = first(r), step(r), last(r)
    U = unit(a)
    V = absoluteunit(U)
    print(io, '(')
    if ustrip(V, s) == 1
        show(io, ustrip(U, a):ustrip(U, b))
    else
        show(io, ustrip(U, a):ustrip(V, s):ustrip(U, b))
    end
    print(io, ')')
    has_unit_spacing(U) && print(io,' ')
    show(io, U)
end

function show(io::IO, r::StepRangeLen{T}) where T<:Quantity
    a,s,b = first(r), step(r), last(r)
    U = unit(a)
    V = absoluteunit(U)
    print(io, '(')
    show(io, StepRangeLen(ustrip(U, a), ustrip(V, s), length(r)))
    print(io, ')')
    has_unit_spacing(U) && print(io,' ')
    show(io, U)
end

function show(io::IO, x::typeof(NoDims))
    print(io, "NoDims")
end

"""
    show(io::IO, x::Unitlike)
Call [`Unitful.showrep`](@ref) on each object in the tuple that is the type
variable of a [`Unitful.Units`](@ref) or [`Unitful.Dimensions`](@ref) object.
"""
function show(io::IO, x::Unitlike)
    showoperators = get(io, :showoperators, false)
    sep = showoperators ? "*" : " "
    isfirst = true
    for y in sortexp(x)
        isfirst || print(io, sep)
        showrep(io, y)
        isfirst = false
    end
    nothing
end

"""
    sortexp(xs)
Sort units to show positive exponents first.
"""
sortexp(xs) = sort!(collect(xs), by = u->signbit(power(u)), alg = InsertionSort)
@generated sortexp(::Dimensions{D}) where D = (sortexp(D)...,)
@generated sortexp(::Units{U}) where U = (sortexp(U)...,)

"""
    showrep(io::IO, x::Unit)
Show the unit, prefixing with any decimal prefix and appending the exponent as
formatted by [`Unitful.superscript`](@ref).
"""
function showrep(io::IO, x::Unit)
    print(io, prefix(x))
    print(io, abbr(x))
    print(io, (power(x) == 1//1 ? "" : superscript(power(x); io=io)))
    nothing
end

"""
    showrep(io::IO, x::Dimension)
Show the dimension, appending any exponent as formatted by
[`Unitful.superscript`](@ref).
"""
function showrep(io::IO, x::Dimension)
    print(io, abbr(x))
    print(io, (power(x) == 1//1 ? "" : superscript(power(x); io=io)))
end

"""
    superscript(i::Rational; io::Union{IO, Nothing} = nothing)
Returns exponents as a string.

This function returns the value as a string. It does not print to `io`. `io` is
only used for IO context values. If `io` contains the `:fancy_exponent`
property and the value is a `Bool`, this value will override the behavior of
fancy exponents.
"""
function superscript(i::Rational; io::Union{IO, Nothing} = nothing)
    if io === nothing
        iocontext_value = nothing
    else
        iocontext_value = get(io, :fancy_exponent, nothing)
    end
    if iocontext_value isa Bool
        fancy_exponent = iocontext_value
    else
        v = get(ENV, "UNITFUL_FANCY_EXPONENTS", Sys.isapple() ? "true" : "false")
        t = tryparse(Bool, lowercase(v))
        fancy_exponent = (t === nothing) ? false : t
    end
    if fancy_exponent
        return i.den == 1 ? superscript(i.num) : string(superscript(i.num), '\u141F', superscript(i.den))
    else
        i.den == 1 ? "^" * string(i.num) : "^" * replace(string(i), "//" => "/")
    end
end

# Taken from SIUnits.jl
superscript(i::Integer) = map(repr(i)) do c
    c == '-' ? '\u207b' :
    c == '1' ? '\u00b9' :
    c == '2' ? '\u00b2' :
    c == '3' ? '\u00b3' :
    c == '4' ? '\u2074' :
    c == '5' ? '\u2075' :
    c == '6' ? '\u2076' :
    c == '7' ? '\u2077' :
    c == '8' ? '\u2078' :
    c == '9' ? '\u2079' :
    c == '0' ? '\u2070' :
    error("unexpected character")
end

if isdefined(Base, :alignment_from_show)
    printed_length(io, x) = Base.alignment_from_show(io, x)
else
    printed_length(io, x) = length(sprint(show, x, context=io))
end

function Base.alignment(io::IO, x::Quantity)
    if isunitless(unit(x))
        return Base.alignment(io, x.val)
    end
    length = printed_length(io, x)
    left, _ = Base.alignment(io, x.val)
    left += BracketStyle(x.val) != NoBrackets()
    return left, length - left
end


================================================
FILE: src/fastmath.jl
================================================
import Base.FastMath

import Base.FastMath: @fastmath,
    FloatTypes,
    ComplexTypes,
    add_fast,
    sub_fast,
    mul_fast,
    div_fast,
    rem_fast,
    cmp_fast,
    # mod_fast,
    eq_fast,
    ne_fast,
    lt_fast,
    le_fast,
    pow_fast,
    sqrt_fast,
    cos_fast,
    sin_fast,
    tan_fast,
    sincos_fast,
    atan_fast,
    hypot_fast,
    max_fast,
    min_fast,
    minmax_fast,
    cis_fast,
    angle_fast,
    fast_op

sub_fast(x::Quantity{T}) where {T <: FloatTypes} = typeof(x)(sub_fast(x.val))

add_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
    Quantity{T,D,U}(add_fast(x.val, y.val))

sub_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
    Quantity{T,D,U}(sub_fast(x.val, y.val))

function mul_fast(x::Quantity{T}, y::Quantity{T}) where {T <: FloatTypes}
    D = dimension(x) * dimension(y)
    U = typeof(unit(x) * unit(y))
    Quantity{T,D,U}(mul_fast(x.val, y.val))
end
function div_fast(x::Quantity{T}, y::Quantity{T}) where {T <: FloatTypes}
    D = dimension(x) / dimension(y)
    U = typeof(unit(x) / unit(y))
    Quantity{T,D,U}(div_fast(x.val, y.val))
end

rem_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
    Quantity{T,D,U}(rem_fast(x.val, y.val))

add_fast(x::Quantity{T}, y::Quantity{T}, z::Quantity{T}, t::Quantity{T}...) where {T <: FloatTypes} =
    add_fast(add_fast(add_fast(x, y), z), t...)
mul_fast(x::Quantity{T}, y::Quantity{T}, z::Quantity{T}, t::Quantity{T}...) where {T <: FloatTypes} =
    mul_fast(mul_fast(mul_fast(x, y), z), t...)

@fastmath begin
    cmp_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
        ifelse(x==y, 0, ifelse(x<y, -1, +1))
end

eq_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
    eq_fast(x.val,y.val)
ne_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
    ne_fast(x.val,y.val)
lt_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
    lt_fast(x.val,y.val)
le_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
    le_fast(x.val,y.val)

@fastmath begin
    abs_fast(x::Quantity{T}) where {T <: ComplexTypes} = hypot(real(x), imag(x))
    abs2_fast(x::Quantity{T}) where {T <: ComplexTypes} = real(x)*real(x) + imag(x)*imag(x)
    conj_fast(x::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =
        Quantity{T,D,U}(T(real(x.val), -imag(x.val)))
    inv_fast(x::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} = conj(x) / abs2(x)
    sign_fast(x::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =
        x == Quantity(0, U()) ? float(zero(x)) : x/abs(x)

    add_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =
        Quantity{T,D,U}(T(real(x.val)+real(y.val), imag(x.val)+imag(y.val)))
    add_fast(x::Quantity{Complex{T},D,U}, b::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)+b.val, imag(x.val)))
    add_fast(a::Quantity{T,D,U}, y::Quantity{Complex{T},D,U}) where {T <: FloatTypes,D,U} =
        Quantity{Complex{T},D,U}(Complex{T}(a.val+real(y.val), imag(y.val)))

    sub_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} =
        Quantity{T,D,U}(T(real(x.val)-real(y.val), imag(x.val)-imag(y.val)))
    sub_fast(x::Quantity{Complex{T},D,U}, b::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)-b.val, imag(x.val)))
    sub_fast(a::Quantity{T,D,U}, y::Quantity{Complex{T},D,U}) where {T <: FloatTypes,D,U} =
        Quantity{Complex{T},D,U}(Complex{T}(a.val-real(y.val), -imag(y.val)))

    function mul_fast(x::Quantity{T}, y::Quantity{T}) where {T <: ComplexTypes}
        D = dimension(x) * dimension(y)
        U = typeof(unit(x) * unit(y))
        Quantity{T,D,U}(T(real(x.val)*real(y.val) - imag(x.val)*imag(y.val),
          real(x.val)*imag(y.val) + imag(x.val)*real(y.val)))
    end
    function mul_fast(x::Quantity{Complex{T}}, b::Quantity{T}) where {T <: FloatTypes}
        D = dimension(x) * dimension(b)
        U = typeof(unit(x) * unit(b))
        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)*b.val, imag(x.val)*b.val))
    end
    function mul_fast(a::Quantity{T}, y::Quantity{Complex{T}}) where {T <: FloatTypes}
        D = dimension(a) * dimension(y)
        U = typeof(unit(a) * unit(y))
        Quantity{Complex{T},D,U}(Complex{T}(a.val*real(y.val), a.val*imag(y.val)))
    end

    @inline function div_fast(x::Quantity{T}, y::Quantity{T}) where {T <: ComplexTypes}
        D = dimension(x) * dimension(y)
        U = typeof(unit(x) * unit(y))
        Quantity{T,D,U}(T(real(x.val)*real(y.val) + imag(x.val)*imag(y.val),
          imag(x.val)*real(y.val) - real(x.val)*imag(y.val))) / abs2(y)
    end
    function div_fast(x::Quantity{Complex{T}}, b::Quantity{T}) where {T <: FloatTypes}
        D = dimension(x) / dimension(b)
        U = typeof(unit(x) / unit(b))
        Quantity{Complex{T},D,U}(Complex{T}(real(x.val)/b.val, imag(x.val)/b.val))
    end
    function div_fast(a::Quantity{T}, y::Quantity{Complex{T}}) where {T <: FloatTypes}
        D = dimension(a) * dimension(y)
        U = typeof(unit(a) * unit(y))
        Quantity{Complex{T},D,U}(Complex{T}(a.val*real(y.val),
            -a.val*imag(y.val))) / abs2(y)
    end

    eq_fast(x::Quantity{T}, y::Quantity{T}) where {T <: ComplexTypes} =
        (real(x)==real(y)) & (imag(x)==imag(y))
    eq_fast(x::Quantity{Complex{T}}, b::Quantity{T}) where {T <: FloatTypes} =
        (real(x)==b) & (imag(x)==zero(b))
    eq_fast(a::Quantity{T}, y::Quantity{Complex{T}}) where {T <: FloatTypes} =
        (a==real(y)) & (zero(a)==imag(y))

    ne_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: ComplexTypes,D,U} = !(x==y)
end

for op in (:+, :-, :*, :/, :(==), :!=, :<, :<=, :cmp, :rem)
    op_fast = fast_op[op]
    @eval begin
        # Fallback method for Quantitys after promotion.
        $op_fast(x::Quantity{T},ys::Quantity{T}...) where {T <: Number} = $op(x,ys...)
    end
end

# exponentiation is not and cannot be type-stable for `Quantity`s,
# so we will not fastmathify it
pow_fast(x::Quantity, y::Integer) = x^y
pow_fast(x::Quantity, y::Rational) = x^y

sqrt_fast(x::Quantity{T}) where {T <: FloatTypes} =
    Quantity(sqrt_fast(x.val), sqrt(unit(x)))

for f in (:cos, :sin, :tan, :sincos, :cis)
    f_fast = fast_op[f]
    @eval $f_fast(x::DimensionlessQuantity) = $f_fast(ustrip(NoUnits, x))
end

atan_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T,D,U} =
    atan_fast(x.val, y.val)

@fastmath begin
    hypot_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
        sqrt(x*x + y*y)

    # Note: we use the same comparison for min, max, and minmax, so
    # that the compiler can convert between them
    max_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
        ifelse(y > x, y, x)
    min_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
        ifelse(y > x, x, y)
    minmax_fast(x::Quantity{T,D,U}, y::Quantity{T,D,U}) where {T <: FloatTypes,D,U} =
        ifelse(y > x, (x,y), (y,x))

    # complex numbers

    angle_fast(x::Quantity{T}) where {T <: ComplexTypes} = atan(imag(x), real(x))
end


================================================
FILE: src/logarithm.jl
================================================
base(::LogInfo{N,B}) where {N,B} = B
prefactor(::LogInfo{N,B,P}) where {N,B,P} = P
zero(x::T) where {T<:Level} = T(zero(x.val))
zero(::Type{X}) where {L,S,T,X<:Level{L,S,T}} = X(zero(T))
one(x::T) where {T<:Level} = one(x.val)
one(::Type{X}) where {L,S,T,X<:Level{L,S,T}} = one(T)
function Base.float(x::Level{L,S}) where {L,S}
    v = float(x.val)
    return Level{L,S,typeof(v)}(v)
end
big(x::Level{L,S}) where {L,S} = Level{L,S}(big(x.val))
"""
    logunit(x::LogScaled)
    logunit(x::Union{Type{<:LogScaled}, MixedUnits})
Returns the logarithmic "units" associated with a `LogScaled` instance, a 
`LogScaled` type, or a `MixedUnits`.

Examples:
```jldoctest
julia> using Unitful

julia> logunit(1*u"dB")
dB

julia> logunit(u"dB")
dB

julia> logunit(u"dB/s")
dB
```

See also: [`unit`](@ref).
"""
function logunit end
logunit(x::Level{L,S}) where {L,S} = MixedUnits{Level{L,S}}()
logunit(x::Type{T}) where {L,S,T<:Level{L,S}} = MixedUnits{Level{L,S}}()

abbr(x::Level{L,S}) where {L,S} = join([abbr(L()), " (", S, ")"])

Base.convert(::Type{LogScaled{L1}}, x::Level{L2,S}) where {L1,L2,S} = Level{L1,S}(x.val)
Base.convert(T::Type{<:Level}, x::Level) = T(x.val)
Base.convert(::Type{Quantity{T,D,U}}, x::Level) where {T,D,U} =
    convert(Quantity{T,D,U}, x.val)
Base.convert(::Type{Quantity{T}}, x::Level) where {T<:Number} = convert(Quantity{T}, x.val)
Base.convert(::Type{T}, x::Quantity) where {L,S,T<:Level{L,S}} = T(x)
Base.convert(::Type{T}, x::Level) where {T<:Real} = T(x.val)

function Base.float(x::Gain{L,S}) where {L,S}
    v = float(x.val)
    return Gain{L,S,typeof(v)}(v)
end
big(x::Gain{L,S}) where {L,S} = Gain{L,S}(big(x.val))
logunit(x::Gain{L,S}) where {L,S} = MixedUnits{Gain{L,S}}()
logunit(x::Type{T}) where {L,S, T<:Gain{L,S}} = MixedUnits{Gain{L,S}}()
abbr(x::Gain{L}) where {L} = abbr(L())
zero(x::T) where {T<:Gain} = T(zero(x.val))
zero(::Type{X}) where {L,S,T, X<:Gain{L,S,T}} = X(zero(T))
one(x::T) where {T<:Gain} = T(zero(x.val))
one(::Type{X}) where {L,S,T, X<:Gain{L,S,T}} = X(zero(T))
function Gain{L}(val::Real) where {L <: LogInfo}
    dimension(val) != NoDims && throw(DimensionError(val,1))
    return Gain{L, :?, typeof(val)}(val)
end
function Gain{L,S}(val::Real) where {L <: LogInfo,S}
    dimension(val) != NoDims && throw(DimensionError(val,1))
    return Gain{L, S, typeof(val)}(val)
end

Base.convert(::Type{Gain{L}}, x::Gain{L,S}) where {L,S} = Gain{L,S}(x.val)
Base.convert(::Type{Gain{L1}}, x::Gain{L2,S}) where {L1,L2,S} = Gain{L1,S}(_gconv(L1,L2,x))

Base.convert(::Type{Gain{L,S}}, x::Gain{L,S}) where {L,S} = Gain{L,S}(x.val)
Base.convert(::Type{Gain{L1,S}}, x::Gain{L2,S}) where {L1,L2,S} = Gain{L1,S}(_gconv(L1,L2,x))
Base.convert(::Type{Gain{L,S1}}, x::Gain{L,S2}) where {L,S1,S2} = Gain{L,S1}(x.val)
Base.convert(::Type{Gain{L1,S1}}, x::Gain{L2,S2}) where {L1,L2,S1,S2} =
    Gain{L1,S1}(_gconv(L1,L2,x))

Base.convert(::Type{Gain{L,S,T}}, x::Gain{L,S}) where {L,S,T} = Gain{L,S,T}(x.val)
Base.convert(::Type{Gain{L1,S,T}}, x::Gain{L2,S}) where {L1,L2,S,T} =
    Gain{L1,S,T}(_gconv(L1,L2,x))
Base.convert(::Type{Gain{L,S1,T}}, x::Gain{L,S2}) where {L,S1,S2,T} =
    Gain{L,S1,T}(x.val)
Base.convert(::Type{Gain{L1,S1,T}}, x::Gain{L2,S2}) where {L1,L2,S1,S2,T} =
    Gain{L1,S1,T}(_gconv(L1,L2,x))

Base.convert(::Type{LogScaled{L1}}, x::Gain{L2}) where {L1,L2} = Gain{L1}(_gconv(L1,L2,x))
Base.convert(::Type{T}, y::Gain) where {T<:Real} = convert(T, uconvert(NoUnits, y))

Base.convert(::Type{G}, x::Real) where {L, G <: Gain{L,:p}} =
    G(ifelse(isrootpower(L), 0.5, 1) * tolog(L, x))
Base.convert(::Type{G}, x::Real) where {L, G <: Gain{L,:rp}} =
    G(ifelse(isrootpower(L), 1, 2) * tolog(L, x))
Base.convert(::Type{<:Gain}, x::Real) = error("$x is not obviously a ratio of power or ",
    "root-power quantities; use `uconvertrp` or `uconvertp` instead.")

function _gconv(L1,L2,x)
    if isrootpower(L1) == isrootpower(L2)
        gain = tolog(L1,fromlog(L2,x.val))
    elseif isrootpower(L1) && !isrootpower(L2)
        gain = tolog(L1,fromlog(L2,0.5*x.val))
    else
        gain = tolog(L1,fromlog(L2,2*x.val))
    end
    return gain
end

tolog(L,S,x) = (1+isrootpower(S)) * prefactor(L()) * (logfn(L()))(x)
tolog(L,x) = (1+isrootpower(L)) * prefactor(L()) * (logfn(L()))(x)
fromlog(L,S,x) = unwrap(S) * expfn(L())( x / ((1+isrootpower(S))*prefactor(L())) )
fromlog(L,x) = expfn(L())( x / ((1+isrootpower(L))*prefactor(L())) )

function Base.show(io::IO, x::MixedUnits{T,U}) where {T,U}
    print(io, abbr(x))
    if x.units != NoUnits
        print(io, " ")
        show(io, x.units)
    end
end

abbr(::MixedUnits{L}) where {L <: Level} = abbr(L(reflevel(L)))
abbr(::MixedUnits{L}) where {L <: Gain} = abbr(L(1))

unit(a::MixedUnits{L,U}) where {L,U} = U()
logunit(a::MixedUnits{L}) where {L} = MixedUnits{L}()
isunitless(::MixedUnits) = false

Base.:*(::MixedUnits, ::MixedUnits) =
    throw(ArgumentError("cannot multiply logarithmic units together."))
Base.:/(::MixedUnits{T}, ::MixedUnits{S}) where {T,S} =
    throw(ArgumentError("cannot divide logarithmic units except to cancel."))
Base.:/(x::MixedUnits{T}, y::MixedUnits{T}) where {T} = x.units / y.units

Base.:*(x::MixedUnits{T}, y::Units) where {T} = MixedUnits{T}(x.units * y)
Base.:*(x::Units, y::MixedUnits) = y * x
Base.:/(x::MixedUnits{T}, y::Units) where {T} = MixedUnits{T}(x.units / y)
Base.:/(x::Units, y::MixedUnits) =
    throw(ArgumentError("cannot divide logarithmic units except to cancel."))

Base.:*(x::Real, y::MixedUnits{Level{L,S}}) where {L,S} =
    (Level{L,S}(fromlog(L,S,x)))*y.units
Base.:*(x::Real, y::MixedUnits{Gain{L,S}}) where {L,S} = (Gain{L,S}(x))*y.units
Base.:*(x::MixedUnits, y::Number) = y * x
Base.:/(x::Number, y::MixedUnits) =
    throw(ArgumentError("cannot divide $x by logarithmic units."))
Base.:/(x::MixedUnits, y::Number) = inv(y) * x

function uconvert(a::Units, x::Level)
    dimension(a) != dimension(x) && throw(DimensionError(a,x))
    return uconvert(a, x.val)
end
function uconvert(a::Units, x::Gain)
    dimension(a) != dimension(x) && throw(DimensionError(a,x))
    uconvert(a, linear(x))
end
uconvert(a::Units, x::Quantity{<:Level}) = uconvert(a, linear(x))
uconvert(a::Units, x::Quantity{<:Gain}) = uconvert(a, linear(x))
function uconvert(a::MixedUnits{Level{L,S}}, x::Number) where {L,S}
    dimension(a) != dimension(x) && throw(DimensionError(a,x))
    q1 = uconvert(unit(unwrap(S))*a.units, linear(x)) / a.units
    return Level{L,S}(q1) * a.units
end
function uconvert(a::MixedUnits{Gain{L,S}}, x::Gain) where {L,S}
    dimension(a) != dimension(x) && throw(DimensionError(a,x))
    return convert(Gain{L,S}, x)
end
function uconvert(a::MixedUnits{Gain{L,S}}, x::Number) where {L,S}
    dimension(a) != dimension(x) && throw(DimensionError(a,x))
    if S == :rp
        return uconvertrp(a, x)
    elseif S == :p
        return uconvertp(a, x)
    else
        error("$x is not obviously a ratio of power or root-power quantities; ",
            "use `uconvertrp` or `uconvertp` instead.")
    end
end

function uconvert(a::MixedUnits{Gain{L,S}}, x::Quantity) where {L,S}
    dimension(a) != dimension(x) && throw(DimensionError(a,x))
    convert(Gain{L,S}, x.val) * convfact(unit(a), unit(x)) * unit(a)
end
function uconvert(a::MixedUnits{Gain{L1,S1,<:Real}}, x::Level{L2,S2}) where {L1,L2,S1,S2}
    dimension(a) != dimension(x) && throw(DimensionError(a,x))
    return Level{L1,S2}(x.val)
end

ustrip(x::Level{L,S}) where {L<:LogInfo,S} = tolog(L,S,x.val/reflevel(x))
ustrip(x::Gain) = x.val

isrootpower(y::IsRootPowerRatio{T}) where {T} = T
isrootpower(y) = isrootpower_dim(dimension(y))
isrootpower_dim(y) =
    error("undefined behavior. Please file an issue with the code needed to reproduce.")

==(x::Gain, y::Level) = ==(y,x)
==(x::Level, y::Gain) = false

for op in (:(==), :isequal)
    @eval Base.$op(x::Level, y::Level) = $op(x.val, y.val)
    @eval Base.$op(x::Gain{L,S}, y::Gain{L,S}) where {L,S} = $op(x.val, y.val)
end

# A consistent `hash` method for `Gain` is impossible with the current promotion rules
# (https://github.com/JuliaPhysics/Unitful.jl/issues/402), therefore we don't define one.
Base.hash(x::Level, h::UInt) = hash(x.val, h)

# Addition and subtraction
for op in (:+, :-)
    @eval Base.$op(x::Level{L,S}, y::Level{L,S}) where {L,S} = Level{L,S}(($op)(x.val, y.val))
    @eval Base.$op(x::Gain{L,S}, y::Gain{L,S}) where {L,S} = Gain{L,S}(($op)(x.val, y.val))
    @eval function Base.$op(x::Gain{L,S1}, y::Gain{L,S2}) where {L,S1,S2}
        if S1 == :?
            return Gain{L,S2}(($op)(x.val, y.val))
        elseif S2 == :?
            return Gain{L,S1}(($op)(x.val, y.val))
        else
            return Gain{L,:?}(($op)(x.val, y.val))
        end
    end
    @eval Base.$op(x::Level{L,S}, y::Gain{L}) where {L,S} =
        Level{L,S}(fromlog(L, S, ($op)(ustrip(x), y.val)))
end
Base.:+(x::Gain, y::Level) = +(y,x)
Base.:-(x::Gain, y::Level) = throw(ArgumentError("cannot subtract a level from a gain."))

# Multiplication and division
leveltype(x::Level{L,S}) where {L,S} = Level{L,S}
Base.:*(x::Level, y::Number) = (leveltype(x))(x.val * y)
Base.:*(x::Level, y::Bool) = (leveltype(x))(x.val * y)    # for method ambiguity
Base.:*(x::Level, y::AbstractQuantity) = *(x.val, y)
Base.:*(x::Level, y::Level) = *(x.val, y.val)
Base.:*(x::Level, y::Gain) = *(promote(x,y)...)

Base.:*(x::Number, y::Level) = *(y,x)
Base.:*(x::Bool, y::Level) = *(y,x)                       # for method ambiguity
Base.:*(x::AbstractQuantity, y::Level) = *(y,x)           # for method ambiguity

gaintype(::Gain{L,S}) where {L,S} = Gain{L,S}
Base.:*(x::Gain, y::Number) = (gaintype(x))(x.val * y)
Base.:*(x::Gain, y::Bool) = (gaintype(x))(x.val * y)      # for method ambiguity
Base.:*(x::Gain, y::AbstractQuantity) = *(y,x)
Base.:*(x::Gain, y::Level) = *(promote(x,y)...)
Base.:*(x::Gain, y::Gain) = *(promote(x,y)...)

Base.:*(x::Number, y::Gain) = *(y,x)
Base.:*(x::Bool, y::Gain) = *(y,x)                        # for method ambiguity
Base.:*(x::AbstractQuantity, y::Gain) =
    isrootpower(x) ? uconvertrp(NoUnits, y) * x : uconvertp(NoUnits, y) * x

for (op1,op2) in ((:*, :+), (:/, :-))
    @eval Base.$op1(x::Gain{L,S}, y::Gain{L,S}) where {L,S} = Gain{L,S}(($op2)(x.val, y.val))
    @eval function Base.$op1(x::Gain{L,S1}, y::Gain{L,S2}) where {L,S1,S2}
        if S1 == :?
            return Gain{L,S2}(($op2)(x.val, y.val))
        elseif S2 == :?
            return Gain{L,S1}(($op2)(x.val, y.val))
        else
            return Gain{L,:?}(($op2)(x.val, y.val))
        end
    end
    @eval Base.$op1(x::Level{L,S}, y::Gain{L}) where {L,S} =
        Level{L,S}(fromlog(L, S, ($op2)(ustrip(x), y.val)))
end

Base.:*(x::Gain{L}, y::Level{L,S}) where {L,S} = Level{L,S}(fromlog(L, S, ustrip(y)+x.val))
Base.:/(x::Gain, y::Level) = throw(ArgumentError("cannot divide a gain by a level."))

Base.:/(x::Level, y::Number) = (leveltype(x))(linear(x) / y)
Base.://(x::Level, y::Number) = (leveltype(x))(linear(x) // y)
Base.:/(x::Level, y::AbstractQuantity) = linear(x) / y
Base.://(x::Level, y::AbstractQuantity) = linear(x) // y
Base.:/(x::Level, y::Level) = linear(x) / linear(y)
Base.://(x::Level, y::Level) = linear(x) // linear(y)
Base.://(x::Level, y::Complex) = linear(x) // y     # ambiguity resolution

Base.://(x::Number, y::Level) = x // linear(y)
Base.:/(x::AbstractQuantity, y::Level) = x / linear(y)
Base.://(x::AbstractQuantity, y::Level) = x // linear(y)
Base.:/(x::AbstractQuantity, y::Gain) =
    isrootpower(x) ? x / uconvertrp(NoUnits, y) : x / uconvertp(NoUnits, y)
Base.://(x::AbstractQuantity, y::Gain) =
    isrootpower(x) ? x // uconvertrp(NoUnits, y) : x // uconvertp(NoUnits, y)

Base.://(x::Level, y::Units) = x/y
Base.://(x::Units, y::Level) = x//linear(y)
Base.://(x::Gain, y::Units) = x/y
Base.://(x::Units, y::Gain) = x//linear(y)

Base.isless(x::T, y::T) where {T<:LogScaled} = isless(x.val, y.val)

function (Base.promote_rule(::Type{Level{L1,S1,T1}}, ::Type{Level{L2,S2,T2}})
        where {L1,L2,S1,S2,T1,T2})
    if L1 == L2
        if S1 == S2
            # Use convert(promote_type(typeof(S1), typeof(S2)), S1) instead of S1?
            return Level{L1, S1, promote_type(T1,T2)}
        else
            return promote_type(T1,T2)
        end
    else
        return promote_type(T1,T2)
    end
end

function Base.promote_rule(::Type{Quantity{T,D,U}}, ::Type{Level{L,R,S}}) where {L,R,S,T,D,U}
    return promote_type(S, Quantity{T,D,U})
end
function Base.promote_rule(::Type{Level{L,R,S}}, ::Type{T}) where {L,R,S,T<:Real}
    return promote_type(S,T)
end
function (Base.promote_rule(::Type{Gain{L1,S1,T1}}, ::Type{Gain{L2,S2,T2}})
        where {L1,L2,S1,S2,T1,T2})
    if L1 == L2
        if S1 == :?
            return Gain{L1,S2,promote_type(T1,T2)}
        elseif S2 == :?
            return Gain{L1,S1,promote_type(T1,T2)}
        else
            return Gain{L1,:?,promote_type(T1,T2)}
        end
    else
        return promote_type(float(T1), float(T2))
    end
end
function Base.promote_rule(::Type{G}, ::Type{N}) where {L,S,T1, G<:Gain{L,S,T1}, N<:Number}
    if S == :?
        error("no automatic promotion of $G and $N.")
    else
        return Gain{L,S,promote_type(float(T1), N)}
    end
end
Base.promote_rule(A::Type{G}, B::Type{L}) where {G<:Gain, L2, L<:Level{L2}} = LogScaled{L2}

function Base.show(io::IO, x::Gain)
    print(io, x.val, " ", abbr(x))
    nothing
end
function Base.show(io::IO, x::Level)
    print(io, ustrip(x), " ", abbr(x))
    nothing
end

function Base.alignment(io::IO, x::Gain)
    length = printed_length(io, x)
    left, _ = Base.alignment(io, x.val)
    return left, length - left
end
function Base.alignment(io::IO, x::Level)
    length = printed_length(io, x)
    left, _ = Base.alignment(io, ustrip(x))
    return left, length - left
end

BracketStyle(::Type{<:Union{Level,Gain}}) = SquareBrackets()

"""
    uconvertp(u::Units, x)
    uconvertp(u::MixedUnits, x)
Generically, this is the same as [`Unitful.uconvert`](@ref). In cases where unit conversion
would be ambiguous without further information (e.g. `uconvert(dB, 10)`), `uconvertp`
presumes ratios are of power quantities.

It is important to note that careless use of this function can lead to erroneous calculations.
Consider `Quantity{<:Gain}` types: it is tempting to use this to transform `-20dB/m` into
`0.1/m`, however this means something fundamentally different than `-20dB/m`. Consider what
happens when you try to compute exponential attenuation by multiplying `0.1/m` by a length.

Examples:
```jldoctest
julia> using Unitful

julia> uconvertp(u"dB", 10)
10.0 dB

julia> uconvertp(NoUnits, 20u"dB")
100.0
```
"""
function uconvertp end
uconvertp(u, x) = uconvert(u, x)    # fallback
uconvertp(::Units{()}, x::Gain{L}) where {L} =
    fromlog(L, ifelse(isrootpower(L), 2, 1)*x.val)
uconvertp(u::T, x::Real) where {L, G <: Gain{L}, T <: MixedUnits{G, <:Units{()}}} =
    convert(Gain{L,:p}, x)
# function uconvertp(a::MixedUnits{Gain{L}}, x::Number) where {L}
#     dimension(a) != dimension(x) && throw(DimensionError(a,x))
#
# end

"""
    uconvertrp(u::Units, x)
    uconvertrp(u::MixedUnits, x)
In most cases, this is the same as [`Unitful.uconvert`](@ref). In cases where unit conversion
would be ambiguous without further information (e.g. `uconvert(dB, 10)`), `uconvertrp`
presumes ratios are of root-power quantities.

It is important to note that careless use of this function can lead to erroneous calculations.
Consider `Quantity{<:Gain}` types: it is tempting to use this to transform `-20dB/m` into
`0.01/m`, however this means something fundamentally different than `-20dB/m`. Consider what
happens when you try to compute exponential attenuation by multiplying `0.01/m` by a length.
"""
function uconvertrp end
uconvertrp(u, x) = uconvert(u, x)
uconvertrp(::Units{()}, x::Gain{L}) where {L} =
    fromlog(L, ifelse(isrootpower(L), 1.0, 0.5)*x.val)
uconvertrp(u::T, x::Real) where {L, G <: Gain{L}, T <: MixedUnits{G, <:Units{()}}} =
    convert(Gain{L,:rp}, x)

"""
    linear(x::Quantity)
    linear(x::Level)
    linear(x::Number) = x
Returns a quantity equivalent to `x` but without any logarithmic scales.

It is important to note that this operation will error for `Quantity{<:Gain}` types. This
is for two reasons:

- `20dB` could be interpreted as either a power or root-power ratio.
- Even if `-20dB/m` were interpreted as, say, `0.01/m`, this means something fundamentally
  different than `-20dB/m`. `0.01/m` cannot be used to calculate exponential attenuation.
"""
linear(x::Quantity{<:Level}) = (x.val.val)*unit(x)
linear(x::Quantity{<:Gain{L,:?}}) where {L} = error("ambiguous how to linearize. Cannot determine ",
    "whether to use `uconvertrp` or `uconvertp` from the type of $x: `$(typeof(x))`.")
linear(x::Quantity{<:Gain{L,:rp}}) where {L} = uconvertrp(NoUnits, x.val)*unit(x)
linear(x::Quantity{<:Gain{L,:p}}) where {L} = uconvertp(NoUnits, x.val)*unit(x)
linear(x::Level) = x.val
linear(x::Gain{L,:rp}) where {L} = uconvertrp(NoUnits, x)
linear(x::Gain{L,:p}) where {L} = uconvertp(NoUnits, x)
linear(x::Gain{L,:?}) where {L} = error("ambiguous how to linearize. Cannot determine ",
    "whether to use `uconvertrp` or `uconvertp` from the type of $x: `$(typeof(x))`.")
linear(x::Number) = x

"""
    logfn(x::LogInfo)
Returns the appropriate logarithm function to use in calculations involving the
logarithmic unit / quantity. For example, decibel-based units yield `log10`,
Neper-based yield `ln`, and so on. Returns `x->log(base, x)` as a fallback.
"""
function lo
Download .txt
gitextract_2l21c_cz/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── CompatHelper.yml
│       ├── TagBot.yml
│       ├── ci.yml
│       └── documentation.yaml
├── .gitignore
├── LICENSE.md
├── NEWS.md
├── Project.toml
├── README.md
├── docs/
│   ├── Project.toml
│   ├── generate_latex_images.jl
│   ├── make.jl
│   └── src/
│       ├── LICENSE.md
│       ├── conversion.md
│       ├── dates.md
│       ├── defaultunits.md
│       ├── display.md
│       ├── extending.md
│       ├── highlights.md
│       ├── index.md
│       ├── latexify.md
│       ├── logarithm.md
│       ├── manipulations.md
│       ├── newunits.md
│       ├── temperature.md
│       ├── trouble.md
│       └── types.md
├── ext/
│   ├── ConstructionBaseUnitfulExt.jl
│   ├── ForwardDiffExt.jl
│   ├── InverseFunctionsUnitfulExt.jl
│   ├── LatexifyExt.jl
│   ├── NaNMathExt.jl
│   └── PrintfExt.jl
├── src/
│   ├── Unitful.jl
│   ├── complex.jl
│   ├── conversion.jl
│   ├── dates.jl
│   ├── dimensions.jl
│   ├── display.jl
│   ├── fastmath.jl
│   ├── logarithm.jl
│   ├── pkgdefaults.jl
│   ├── promotion.jl
│   ├── quantities.jl
│   ├── range.jl
│   ├── types.jl
│   ├── units.jl
│   ├── user.jl
│   └── utils.jl
└── test/
    ├── dates.jl
    └── runtests.jl
Condensed preview — 52 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (526K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 255,
    "preview": "# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\nversion: 2\nupda"
  },
  {
    "path": ".github/workflows/CompatHelper.yml",
    "chars": 430,
    "preview": "name: CompatHelper\non:\n  schedule:\n    - cron: 8 14 * * *\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - n"
  },
  {
    "path": ".github/workflows/TagBot.yml",
    "chars": 362,
    "preview": "name: TagBot\non:\n  issue_comment:\n    types:\n      - created\n  workflow_dispatch:\njobs:\n  TagBot:\n    if: github.event_n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1995,
    "preview": "name: CI\n\non:\n  push:\n    branches: \"master\"\n    tags: [\"*\"]\n    paths:\n      - '.github/workflows/ci.yml'\n      - 'src/"
  },
  {
    "path": ".github/workflows/documentation.yaml",
    "chars": 1041,
    "preview": "name: Documentation\n\non:\n  push:\n    branches: \"master\"\n    tags: [\"*\"]\n    paths:\n      - '.github/workflows/documentat"
  },
  {
    "path": ".gitignore",
    "chars": 549,
    "preview": "# Files generated by invoking Julia with --code-coverage\n*.jl.cov\n*.jl.*.cov\n\n# Files generated by invoking Julia with -"
  },
  {
    "path": "LICENSE.md",
    "chars": 2059,
    "preview": "The Unitful.jl package is licensed under the MIT \"Expat\" License:\n\n> Copyright (c) 2016: California Institute of Technol"
  },
  {
    "path": "NEWS.md",
    "chars": 45788,
    "preview": "# Unitful.jl changelog\n\n## v1.28.0 (2026-01-29)\n\n* ![Feature:](https://img.shields.io/badge/-feature-green) Dimensionles"
  },
  {
    "path": "Project.toml",
    "chars": 2055,
    "preview": "name = \"Unitful\"\nuuid = \"1986cc42-f94f-5a68-af5c-568840ba703d\"\nversion = \"1.28.0\"\n\n[deps]\nConstructionBase = \"187b0558-2"
  },
  {
    "path": "README.md",
    "chars": 3923,
    "preview": "[![CI](https://github.com/JuliaPhysics/Unitful.jl/workflows/CI/badge.svg)](https://github.com/JuliaPhysics/Unitful.jl/ac"
  },
  {
    "path": "docs/Project.toml",
    "chars": 634,
    "preview": "[deps]\nDates = \"ade2ca70-3891-5945-98fb-dc099432e06a\"\nDocumenter = \"e30172f5-a6a5-5a46-863b-614d45cd2de4\"\nFontconfig = \""
  },
  {
    "path": "docs/generate_latex_images.jl",
    "chars": 5234,
    "preview": "using LaTeXStrings, Unitful, Latexify\nimport tectonic_jll # needed for lightweight LaTeX render\nusing Fontconfig: format"
  },
  {
    "path": "docs/make.jl",
    "chars": 1328,
    "preview": "using Documenter, Unitful, Dates\n\n@info \"Generating latex images for documentation\"\ninclude(\"generate_latex_images.jl\")\n"
  },
  {
    "path": "docs/src/LICENSE.md",
    "chars": 74,
    "preview": "# License\n\n```@eval\nusing Markdown\nopen(Markdown.parse, \"LICENSE.md\")\n```\n"
  },
  {
    "path": "docs/src/conversion.md",
    "chars": 9676,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Conversion/promotion\n\n## Converting between units\n\nSince `conv"
  },
  {
    "path": "docs/src/dates.md",
    "chars": 4406,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Interoperability with the `Dates` standard library\n\n[Julia's `"
  },
  {
    "path": "docs/src/defaultunits.md",
    "chars": 4315,
    "preview": "# Pre-defined units and сonstants\n\nIn the following, only non-prefixed units are listed. To get a more detailed informat"
  },
  {
    "path": "docs/src/display.md",
    "chars": 624,
    "preview": "# How units are displayed\n\nBy default, exponents on units or dimensions are indicated using Unicode superscripts on\nmacO"
  },
  {
    "path": "docs/src/extending.md",
    "chars": 4457,
    "preview": "# Extending Unitful\n\n## Making your own units package\n\nNew units or dimensions can be defined from the Julia REPL or fro"
  },
  {
    "path": "docs/src/highlights.md",
    "chars": 2215,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Highlighted features\n\n## Dispatch on dimensions\n\nConsider the "
  },
  {
    "path": "docs/src/index.md",
    "chars": 4432,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Unitful.jl\n\nA Julia package for physical units. Available\n[her"
  },
  {
    "path": "docs/src/latexify.md",
    "chars": 5414,
    "preview": "# Latexify extension\n\nUnitful has an extension for [Latexify](https://github.com/korsbo/Latexify.jl), which was formerly"
  },
  {
    "path": "docs/src/logarithm.md",
    "chars": 14474,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Logarithmic scales\n\n!!! note \n\n    Logarithmic scales should b"
  },
  {
    "path": "docs/src/manipulations.md",
    "chars": 951,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\n    using InverseFunctions\nend\n```\n# Manipulating units\n\n## Unitful stri"
  },
  {
    "path": "docs/src/newunits.md",
    "chars": 2285,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Defining new units\n\n!!! note\n    Logarithmic units should not "
  },
  {
    "path": "docs/src/temperature.md",
    "chars": 3775,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\n    using Unitful:AffineError\nend\n```\n# Temperature scales\n\nTemperatures"
  },
  {
    "path": "docs/src/trouble.md",
    "chars": 3248,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Troubleshooting\n\n## Why do unit conversions yield rational num"
  },
  {
    "path": "docs/src/types.md",
    "chars": 2266,
    "preview": "```@meta\nDocTestSetup = quote\n    using Unitful\nend\n```\n# Types\n\n## Overview\nWe define a [`Unitful.Unit{U,D}`](@ref) typ"
  },
  {
    "path": "ext/ConstructionBaseUnitfulExt.jl",
    "chars": 192,
    "preview": "module ConstructionBaseUnitfulExt\nusing Unitful\nimport ConstructionBase: constructorof\n\nconstructorof(::Type{Unitful.Qua"
  },
  {
    "path": "ext/ForwardDiffExt.jl",
    "chars": 202,
    "preview": "module ForwardDiffExt\nusing Unitful\nusing ForwardDiff\n\nfunction Base.convert(d::Type{ForwardDiff.Dual{T, V, N}}, q::Quan"
  },
  {
    "path": "ext/InverseFunctionsUnitfulExt.jl",
    "chars": 229,
    "preview": "module InverseFunctionsUnitfulExt\nusing Unitful\nimport InverseFunctions: inverse\n\n# `true` plays the role of 1, but does"
  },
  {
    "path": "ext/LatexifyExt.jl",
    "chars": 12109,
    "preview": "#=========================================#\n# Extension for Unitful.jl + Latexify.jl, #\n# based on UnitfulLatexify.jl by"
  },
  {
    "path": "ext/NaNMathExt.jl",
    "chars": 216,
    "preview": "module NaNMathExt\nusing Unitful\nimport NaNMath\n\nNaNMath.sqrt(q::Unitful.AbstractQuantity) = NaNMath.sqrt(ustrip(q))*sqrt"
  },
  {
    "path": "ext/PrintfExt.jl",
    "chars": 836,
    "preview": "module PrintfExt\n\nusing Printf\nusing Unitful\nusing Unitful: AbstractQuantity\n\nPrintf.plength(f::Printf.Spec{<:Printf.Int"
  },
  {
    "path": "src/Unitful.jl",
    "chars": 2777,
    "preview": "module Unitful\n\nimport Base: ==, <, <=, +, -, *, /, //, ^, isequal, hash\nimport Base: show, convert\nimport Base: abs, ab"
  },
  {
    "path": "src/complex.jl",
    "chars": 1167,
    "preview": "# This file is meant to provide all the methods in\n# https://github.com/JuliaLang/julia/blob/master/base/complex.jl that"
  },
  {
    "path": "src/conversion.jl",
    "chars": 5334,
    "preview": "\"\"\"\n    convfact(s::Units, t::Units)\nFind the conversion factor from unit `t` to unit `s`, e.g., `convfact(m, cm) == 1//"
  },
  {
    "path": "src/dates.jl",
    "chars": 7910,
    "preview": "# Conversion from and to types from the `Dates` stdlib\n\n# Dates.FixedPeriod\n\nfor (period, unit) = ((Dates.Week, wk), (Da"
  },
  {
    "path": "src/dimensions.jl",
    "chars": 2633,
    "preview": "\"\"\"\n```\n*(a0::Dimensions, a::Dimensions...)\n```\n\nGiven however many dimensions, multiply them together.\n\nCollect [`Unitf"
  },
  {
    "path": "src/display.jl",
    "chars": 8053,
    "preview": "# Convenient dictionary for mapping powers of ten to an SI prefix.\nconst prefixdict = Dict(\n    -24 => \"y\",\n    -21 => \""
  },
  {
    "path": "src/fastmath.jl",
    "chars": 7281,
    "preview": "import Base.FastMath\n\nimport Base.FastMath: @fastmath,\n    FloatTypes,\n    ComplexTypes,\n    add_fast,\n    sub_fast,\n   "
  },
  {
    "path": "src/logarithm.jl",
    "chars": 19200,
    "preview": "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("
  },
  {
    "path": "src/pkgdefaults.jl",
    "chars": 35811,
    "preview": "# Default dimensions and their abbreviations.\n# The dimension symbols are generated by tab completion: \\bfL is 𝐋, etc.\n#"
  },
  {
    "path": "src/promotion.jl",
    "chars": 4822,
    "preview": "\"\"\"\n    promote_unit(::Units, ::Units...)\nGiven `Units` objects as arguments, this function returns a `Units` object app"
  },
  {
    "path": "src/quantities.jl",
    "chars": 21565,
    "preview": "# This is a generated function to avoid determining the dimensions of a given\n# set of units each time a new quantity is"
  },
  {
    "path": "src/range.jl",
    "chars": 11069,
    "preview": "const colon = Base.:(:)\n\nimport Base: ArithmeticRounds\nimport Base: OrderStyle, Ordered, ArithmeticStyle, ArithmeticWrap"
  },
  {
    "path": "src/types.jl",
    "chars": 11114,
    "preview": "\n\"\"\"\n    abstract type Unitlike end\nRepresents units or dimensions. Dimensions are unit-like in the sense that they are\n"
  },
  {
    "path": "src/units.jl",
    "chars": 11449,
    "preview": "@generated function *(a0::FreeUnits, a::FreeUnits...)\n\n    # Sort the units uniquely. This is a generated function so th"
  },
  {
    "path": "src/user.jl",
    "chars": 27391,
    "preview": "\"\"\"\n    register(unit_module::Module)\nMakes Unitful aware of units defined in a new unit module, including making the\n[`"
  },
  {
    "path": "src/utils.jl",
    "chars": 7863,
    "preview": "@inline isunitless(::Units) = false\n@inline isunitless(::Units{()}) = true\n\n@inline numtype(::AbstractQuantity{T}) where"
  },
  {
    "path": "test/dates.jl",
    "chars": 52921,
    "preview": "@testset \"Dates stdlib\" begin\n    @testset \"> dimension, numtype, unit\" begin\n        for (T,u) = ((Nanosecond, u\"ns\"), "
  },
  {
    "path": "test/runtests.jl",
    "chars": 121879,
    "preview": "using Unitful\nusing Test, LinearAlgebra, Random, ConstructionBase, InverseFunctions, Printf\nimport Unitful: DimensionErr"
  }
]

About this extraction

This page contains the full source code of the ajkeller34/Unitful.jl GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 52 files (490.5 KB), approximately 162.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!