Skip to content


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


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

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

julia> @code_warntype square(1.0u"m")
  x::Quantity{Float64, Dimensions:{𝐋}, Units:{m}}

      return $(Expr(:invoke, MethodInstance for ^(::Quantity{Float64, Dimensions:{𝐋}, Units:{m}}, ::Int64), :(^), :(x), 2))

In Julia 0.6, constant literal integers are lowered specially for exponentiation. (See Julia PR #20530 for details.) In this case, type stability can be maintained:

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

julia> @code_warntype square(1.0u"m")
  x::Quantity{Float64, Dimensions:{𝐋}, Units:{m}}

      $(Expr(:inbounds, false))
      # meta: location /Users/ajkeller/.julia/v0.6/Unitful/src/Unitful.jl literal_pow 1080
      SSAValue(0) = (Core.getfield)(x::Quantity{Float64, Dimensions:{𝐋}, Units:{m}}, :val)::Float64
      # meta: pop location
      $(Expr(:inbounds, :pop))
      return $(Expr(:new, Quantity{Float64, Dimensions:{𝐋^2}, Units:{m^2}}, :((Base.mul_float)(SSAValue(0), SSAValue(0))::Float64)))
  end::Quantity{Float64, Dimensions:{𝐋^2}, Units:{m^2}}

Because the functions inv and sqrt are raising a Quantity to a fixed power (-1 and 1/2, respectively), we can use a generated function to ensure type stability in these cases. Also note that squaring a Quantity can be type-stable in either Julia 0.5 or 0.6 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:

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

Other random problems

If using units with some of the unsigned types... well, I'm not sure what you are doing, but you should be aware of this:

julia> using Unitful: m,cm

julia> uconvert(m,0x01cm)   # the user means cm, not 0x01c*m
0x001c m

This behavior is a consequence of a Julia issue that has recently been fixed and will no longer be a problem in future Julia versions.

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.