This library implements fixed-point number types. A fixed-point number represents a fractional, or non-integral, number. In contrast with the more widely known floating-point numbers, with fixed-point numbers the decimal point doesn't "float": fixed-point numbers are effectively integers that are interpreted as being scaled by a constant factor. Consequently, they have a fixed number of digits (bits) after the decimal (radix) point.
Fixed-point numbers can be used to perform arithmetic. Another practical application is to implicitly rescale integers without modifying the underlying representation.
This library exports two categories of fixed-point types. Fixed-point types are used like any other number: they can be added, multiplied, raised to a power, etc. In some cases these operations result in conversion to floating-point types.
Type hierarchy and interpretationThis library defines an abstract type FixedPoint{T <: Integer, f}
as a subtype of Real
. The parameter T
is the underlying machine representation and f
is the number of fraction bits.
For T<:Signed
(a signed integer), there is a fixed-point type Fixed{T, f}
; for T<:Unsigned
(an unsigned integer), there is the Normed{T, f}
type. However, there are slight differences in behavior that go beyond signed/unsigned distinctions.
The Fixed{T,f}
types use 1 bit for sign, and f
bits to represent the fraction. For example, Fixed{Int8,7}
uses 7 bits (all bits except the sign bit) for the fractional part. The value of the number is interpreted as if the integer representation has been divided by 2^f
. Consequently, Fixed{Int8,7}
numbers x
satisfy
-1.0 = -128/128 ≤ x ≤ 127/128 ≈ 0.992.
because the range of Int8
is from -128 to 127.
In contrast, the Normed{T,f}
, with f
fraction bits, map the closed interval [0.0,1.0] to the span of numbers with f
bits. For example, the N0f8
type (aliased to Normed{UInt8,8}
) is represented internally by a UInt8
, and makes 0x00
equivalent to 0.0
and 0xff
to 1.0
. Consequently, Normed
numbers are scaled by 2^f-1
rather than 2^f
. The type aliases N6f10
, N4f12
, N2f14
, and N0f16
are all based on UInt16
and reach the value 1.0
at 10, 12, 14, and 16 bits, respectively (0x03ff
, 0x0fff
, 0x3fff
, and 0xffff
). The NXfY
notation is used for compact printing and the fY
component informs about the number of fractional bits and X+Y
equals the number of underlying bits used.
To construct such a number, use 1.3N4f12
, N4f12(1.3)
, convert(N4f12, 1.3)
, Normed{UInt16,12}(1.3)
, or reinterpret(N4f12, 0x14cc)
. The last syntax means to construct a N4f12
from the UInt16
value 0x14cc
.
More generally, an arbitrary number of bits from any of the standard unsigned integer widths can be used for the fractional part. For example: Normed{UInt32,16}
, Normed{UInt64,3}
, Normed{UInt128,7}
.
You can perform mathematical operations with FixedPoint
numbers, but keep in mind that they are vulnerable to both rounding and overflow. For example:
julia> x = N0f8(0.8) 0.8N0f8 julia> float(x) + x 1.6f0 julia> x + x 0.596N0f8
This is a consequence of the rules that govern overflow in integer arithmetic:
julia> y = reinterpret(x) # `reinterpret(x::FixedPoint)` reinterprets as the underlying "raw" type 0xcc julia> reinterpret(N0f8, y + y) # add two UInt8s and then reinterpret as N0f8 0.596N0f8
Similarly,
julia> x = eps(N0f8) # smallest nonzero `N0f8` number 0.004N0f8 julia> x*x 0.0N0f8
which is rounding-induced underflow. Finally,
julia> x = N4f12(15) 15.0N4f12 julia> x*x ERROR: ArgumentError: Normed{UInt16,12} is a 16-bit type representing 65536 values from 0.0 to 16.0037; cannot represent 225.0 Stacktrace: [1] throw_converterror(::Type{Normed{UInt16,12}}, ::Float32) at /home/tim/.julia/dev/FixedPointNumbers/src/FixedPointNumbers.jl:251 [2] _convert at /home/tim/.julia/dev/FixedPointNumbers/src/normed.jl:77 [inlined] [3] FixedPoint at /home/tim/.julia/dev/FixedPointNumbers/src/FixedPointNumbers.jl:51 [inlined] [4] convert at ./number.jl:7 [inlined] [5] *(::Normed{UInt16,12}, ::Normed{UInt16,12}) at /home/tim/.julia/dev/FixedPointNumbers/src/normed.jl:254 [6] top-level scope at REPL[16]:1
In some circumstances, it may make most sense to think of FixedPoint
numbers as storage types rather than computational types. You can call float(x)
to convert x
to a floating-point equivalent that is reasonably safe for computation; in the type domain, floattype(T::Type)
returns the corresponding type. Note that in some cases floattype(T)
differs from float
's behavior on the corresponding "raw" type:
julia> float(UInt8) Float64 julia> floattype(N0f8) Float32
Because of the role of FixedPointNumbers in domains such as image-processing, this package tries to limit the expansion of the number of bits needed to store results.
Contributing to this packagePlease see CONTRIBUTING.md for information about improving this package.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4