Provides LogFixPoint16 - a (software-implemented) 16-bit logarithmic fixed-point number format with adjustable numbers of integer and fraction bits.
julia> using LogFixPoint16s
julia> v = LogFixPoint16.(rand(Float32,5))
5-element Array{LogFixPoint16,1}:
LogFixPoint16(0.8925083)
LogFixPoint16(0.4919428)
LogFixPoint16(0.69759846)
LogFixPoint16(0.25616693)
LogFixPoint16(0.57248604)
julia> sum(v)
LogFixPoint16(2.9139352)Exports LogFixPoint16, iszero, isnan, signbit, zero, nan, floatmin, floatmax, one, -, inv, *, / , +, -, sqrt, nextfloat, prevfloat, ==, <=, >, >=, show, bitstring as well as conversions to and from Float64, Float32, Float16, Int.
Although LogFixPoint16 is always a 16-bit format, the number of fraction bits (in exchange for integer bits) can be adjusted between 7 and 11. For 7 fraction bits, LogFixPoint16 has a similar dynamic range-precision trade-off as BFloat16; 10 fraction bits are similar to Float16.
julia> LogFixPoint16s.set_nfrac(7)
┌ Warning: LogFixPoint16 was changed to 8 integer and 7 fraction bits.
└ @ Main.LogFixPoint16s ~/git/LogFixPoint16s.jl/src/LogFixPoint16s.jl:24Furthermode the rounding mode can be changed from round-to-nearest in linear space (default) to log space
julia> LogFixPoint16s.set_rounding_mode(:log)
┌ Warning: LogFixPoint16 rounding mode changed to round to nearest in log-space.
└ @ LogFixPoint16s ~/.julia/packages/LogFixPoint16s/TGYbV/src/change_format.jl:48The two arguments :lin and :log are allowed.
A real number x is encoded in LogFixPoint16 as
x = (-1)^s * 2^k
with s being the sign bit and k = i+f the fixed-point number in the exponent, consisting of a signed integer i and a fraction f, which is defined as the significant bits for floating-point numbers. E.g. the number 3 is encoded as
julia> bitstring(LogFixPoint16(3),:split)
"0 1000001 10010110"The sign bit is 0, the sign bit of the signed integer is 1 (meaning + due to the biases excess representation) such that the integer bits equal to 1. The fraction bits are 1/2 + 1/16 + 1/64 + 1/128. Together this is
0 1000001 10010110 = +2^(1 + 1/2 + 1/16 + 1/64 + 1/128) = 2^1.5859375 ≈ 3
The only exceptions are the bitpatterns 0x0000 (zero) and 0x8000 (Not-a-Real, NaR). The smallest/largest representable numbers are (6 integer bits, 9 fraction bits)
julia> floatmin(LogFixPoint16)
LogFixPoint16(2.3314606e-10)
julia> floatmax(LogFixPoint16)
LogFixPoint16(4.2891566e9)Logarithmic fixed-point numbers are placed equi-distantly on a log-scale. Consequently, their decimal precision is perfectly flat throughout the dynamic range of representable numbers. In contrast, floating-point numbers are only equi-distant in logarithmic space when the significand is held fixed; the significant bits, however, are linearly spaced.
As a consequence there is no rounding error for logarithmic fixed-point numbers in multiplication, division, power of 2 or square root - similarly as there is no rounding error for fixed-point numbers for addition and subtraction - as long as no over or underflow occurs.
LogFixPoint16 with 10 fraction bits have a similar decimal precision / dynamic range trade-off as Float16, and 7 fraction bits are similar to BFloat16. However, these decimal precision only apply to additions, as multiplications are rounding error-free. LogFixPoint16s.jl also allows additionally for 8,9 or 11 fraction bits, which are not shown.
Although LogFixPoint16s are software-emulated, they are considerably fast. Define some matrices
julia> using LogFixPoint16s, BenchmarkTools
julia> A = rand(Float32,1000,1000);
julia> B = rand(Float32,1000,1000);
julia> C,D = Float16.(A),Float16.(B);
julia> E,F = LogFixPoint16.(A),LogFixPoint16.(B);And then benchmark via @btime +($A,$B): and so on. Then relative to Float64 performance for addition:
| Operation | Float64 | Float32 | BFloat16 | Float16 | LogFixPoint16 |
|---|---|---|---|---|---|
| Addition (+) | 1200μs | 500μs | 400μs | 1800μs | 6500μs |
| Multiplication (.*) | 1200μs | 500μs | 400μs | 2500μs | 250μs |
| Power (.^2) | 700μs | 300μs | 2800μs | 1000μs | 700μs (*) |
| Square-root (sqrt.) | 1800μs | 900μs | 1800μs | 1200μs | 170μs |
On an Intel i5 (Ice Lake). (*) via power2.
LogFixPoint16s.jl is registered in the Julia Registry, so simply do
julia> ] add LogFixPoint16swhere ] opens the package manager.
