Skip to content

Commit b52b05f

Browse files
committed
Added MFPUtils submodule
1 parent 32fbb7d commit b52b05f

12 files changed

+228
-32
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "MicroFloatingPoints"
22
uuid = "6e0295d3-a2ae-4d9e-ab31-7b55fc0f4333"
33
authors = ["Frédéric Goualard <[email protected]>"]
4-
version = "1.1.0"
4+
version = "1.2.0"
55

66
[deps]
77
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ julia> inexact()
1616
true
1717
```
1818

19-
<!-- Disabling this section pending approval in the general registry.
19+
2020
## Installation
2121

2222
The package can be installed with the Julia package manager. From the Julia REPL, type `]` to enter the Pkg REPL mode and run:
@@ -30,7 +30,9 @@ Or, equivalently, via the Pkg API:
3030
```julia
3131
julia> import Pkg; Pkg.add("MicroFloatingPoints")
3232
```
33-
-->
33+
34+
Note that the `matplotlib` Python package must be available through `PyCall`.
35+
3436

3537
## Documentation
3638

docs/make.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ using Documenter, Random
22
using MicroFloatingPoints
33
using MicroFloatingPoints.MFPRandom
44
using MicroFloatingPoints.MFPPlot
5+
using MicroFloatingPoints.MFPUtils
56

6-
DocMeta.setdocmeta!(MicroFloatingPoints, :DocTestSetup, :(using MicroFloatingPoints, MicroFloatingPoints.MFPRandom, MicroFloatingPoints.MFPPlot); recursive=true)
7+
DocMeta.setdocmeta!(MicroFloatingPoints, :DocTestSetup, :(using MicroFloatingPoints, MicroFloatingPoints.MFPRandom, MicroFloatingPoints.MFPPlot, MicroFloatingPoints.MFPUtils); recursive=true)
78

89
makedocs(
910
sitename="The MicroFloatingPoints Documentation",
1011
authors = "Frédéric Goualard",
1112
modules = [MicroFloatingPoints, MicroFloatingPoints.MFPRandom, MicroFloatingPoints.MFPPlot],
1213
format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"),
1314
pages = ["Home" => "index.md"
14-
"Installation" => "installation.md"
1515
"A Guided Tour" => "guided-tour.md"
1616
"Manual" => "manual.md"
1717
"Developer Documentation" => "developer.md"

docs/src/guided-tour.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ CurrentModule = MicroFloatingPoints
99
# A guided tour
1010

1111

12-
The `MicroFloatingPoints` package is organized into three modules:
12+
The `MicroFloatingPoints` package is organized into four modules:
1313

1414
- `MicroFloatingPoints`: the main module containing the definition of the parameterized type `Floatmu` and the associated methods;
15+
- `MicroFloatingPoints.MFPUtils`: a module providing miscellaneous utility functions for the `Floatmu` type;
1516
- `MicroFloatingPoints.MFPPlot`: a module offering various graphical ways to display `Floatmu` floating-point numbers;
1617
- `MicroFloatingPoints.MFPRandom`: the module overloading [`Random.rand`](https://docs.julialang.org/en/v1/stdlib/Random/#Base.rand) to produce `Floatmu` random values.
1718

docs/src/index.md

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ The `MicroFloatingPoints` package allows to manipulate small [IEEE 754](https://
44

55
The library may serve to exemplify the behavior of IEEE 754 floating-point numbers in a systematic way through the use of very small formats.
66

7+
## Presentation
8+
79
At its core, the package defines a new type `Floatmu` parameterized by two integers:
810

911
- `szE`, the number of bits used to represent the exponent;
@@ -43,3 +45,20 @@ It is also possible to emulate more established formats such as:
4345
- Pixar's PXR24: `Floatmu{8,15}`
4446
- and many more…
4547

48+
## Installation
49+
50+
The package can be installed with the Julia package manager. From the Julia REPL, type `]` to enter the Pkg REPL mode and run:
51+
52+
```julia
53+
pkg> add MicroFloatingPoints
54+
```
55+
56+
Or, equivalently, via the Pkg API:
57+
58+
```julia
59+
julia> import Pkg; Pkg.add("MicroFloatingPoints")
60+
```
61+
62+
Note that the `matplotlib` Python package must be available through `PyCall`.
63+
64+

docs/src/installation.md

-16
This file was deleted.

docs/src/manual.md

+34
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ DocTestSetup = quote
33
using Distributions, Random
44
using MicroFloatingPoints
55
using MicroFloatingPoints.MFPPlot, MicroFloatingPoints.MFPRandom
6+
using MicroFloatingPoints.MFPUtils
67
end
78
CurrentModule = MicroFloatingPoints
89
```
@@ -259,6 +260,18 @@ true
259260

260261
Note that, in the first example, the result of the computation needed rounding, while in the second example, the output is representable but one of the intermediary computation needed rounding.
261262

263+
## The `MicroFloatingPoints.MFPUtils` module
264+
265+
```@meta
266+
CurrentModule = MicroFloatingPoints.MFPUtils
267+
```
268+
269+
The `MicroFloatingPoints.MFPUtils` module offers some utiliy functions to be used either by other modules of the `MicroFloatingPoints` package or directly by the end user.
270+
271+
```@docs
272+
vertical_popcount(T::Vector{Floatmu{szE,szf}}) where {szE,szf}
273+
```
274+
262275

263276
## The `MicroFloatingPoints.MFPRandom` module
264277

@@ -356,3 +369,24 @@ savefig("realline_Floatmu23b.svg"); nothing # hide
356369
<img src="./realline_Floatmu23b.svg" alt="Floatmu{2,3} finite and infinite values" />
357370
</div>
358371
```
372+
373+
```@docs
374+
bits_histogram(T::Vector{Floatmu{szE,szf}}) where {szE,szf}
375+
```
376+
377+
```@setup bits-histogram-example
378+
using MicroFloatingPoints, MicroFloatingPoints.MFPPlot, PyPlot
379+
plt.figure()
380+
```
381+
382+
```@repl bits-histogram-example
383+
T=collect(FloatmuIterator(Floatmu{3,5},0.0,1.0,2.0^-6));
384+
bits_histogram(T)
385+
savefig("bits_histogram.svg"); nothing # hide
386+
```
387+
388+
```@raw html
389+
<div style="text-align: center">
390+
<img src="./bits_histogram.svg" alt="Floatmu{3,4} bits histogram in [0, 1]" />
391+
</div>
392+
```

src/MFPPlot.jl

+90-9
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ module MFPPlot
2222

2323
using PyPlot
2424
using ..MicroFloatingPoints
25+
using ..MicroFloatingPoints.MFPUtils: vertical_popcount
2526

2627
export real_line
28+
export bits_histogram
2729

2830
"""
2931
real_line(start::Floatmu{szE,szf}, stop::Floatmu{szE,szf};
@@ -33,17 +35,22 @@ export real_line
3335
ticks = true,
3436
fpcolorsub = "purple", fpcolornorm = "blue",
3537
fpcolorinf="orange") where {szE,szf}
38+
real_line(T::Vector{Floatmu{szE,szf}};
39+
ticks = true, fpcolorsub = "purple", fpcolornorm = "blue",
40+
fpcolorinf="orange") where {szE,szf}
41+
42+
Draw floats on the real line.
3643
3744
The first version draws the real line between `start` and `stop` and displays all floating-point
3845
numbers with `sze` bits exponent and `szf` bits fractional part. The second version draws all finite
3946
floating-point for the format `Floatmu{szE,szf}` and adds the infinities where the next/previous
40-
float would be with the format `Floatmu{szE+1,szf}`.
47+
float would be with the format `Floatmu{szE+1,szf}`. The third version draws all floats in the
48+
vector `T`.
4149
50+
In the first version, both parameters `start` and `stop` must be finite. An `ArgumentError` exception
51+
is raised otherwise. The same goes for all values in `T` for the third version.
4252
43-
Both parameters `start` and `stop` must be finite. An `ArgumentError` exception
44-
is raised otherwise.
45-
46-
Both versions return the figure used for the plot.
53+
All versions return the figure used for the plot.
4754
4855
The figure may be customized through the named parameters:
4956
- `ticks`: if `true`, draws a vertical line for each float and adds the value below. If
@@ -57,30 +64,73 @@ The figure may be customized through the named parameters:
5764
```@repl
5865
real_line(-floatmax(Floatmu{2,2}),floatmax(Floatmu{2,2}));
5966
real_line(Floatmu{2,2});
67+
real_line(Floatmu{2,2}[-3.5,0.25,1.5,2.0])
6068
```
6169
"""
6270
function real_line end
6371

72+
73+
function real_line(T::Vector{Floatmu{szE,szf}};
74+
ticks = true, fpcolorsub = "purple", fpcolornorm = "blue",
75+
fpcolorinf="orange") where {szE,szf}
76+
all(isfinite,T) || throw(ArgumentError("parameters must be finite"))
77+
(lmost, rmost) = extrema(T)
78+
normal_height = 0.04*(convert(Float64,rmost)-convert(Float64,lmost))
79+
subnormal_height = .8*normal_height
80+
plt.axis("off")
81+
fig=plot([lmost,rmost],[0,0],"k-")
82+
for v in T
83+
if issubnormal(v)
84+
if ticks
85+
plot([v,v],[-subnormal_height,subnormal_height],"-",color=fpcolorsub)
86+
text(v,-normal_height,string(v),fontsize=8,ha="center",va="top",
87+
rotation=90,color=fpcolorsub)
88+
else
89+
plot(v,0,marker=".",color=fpcolorsub)
90+
end
91+
else
92+
if ticks
93+
plot([v,v],[-normal_height,normal_height],"-",color=fpcolornorm)
94+
if v == 0.0
95+
text(0,-1.1*normal_height,L"\pm 0",fontsize=8,ha="center",va="top",
96+
rotation=90,color=fpcolornorm)
97+
else
98+
text(v,-1.1*normal_height,string(v),fontsize=8,ha="center",va="top",
99+
rotation=90,color=fpcolornorm)
100+
end
101+
else
102+
plot(v,0,marker=".",color=fpcolornorm)
103+
end
104+
end
105+
end
106+
return fig
107+
end
108+
109+
64110
function real_line(start::Floatmu{szE,szf}, stop::Floatmu{szE,szf};
65111
ticks = true, fpcolorsub = "purple", fpcolornorm = "blue") where {szE,szf}
112+
# This version could be rewritten as:
113+
# `real_line(collect(FloatmuIterator(start,stop)))`
114+
# but is not to benefit from the on-demand generation of floats with
115+
# the FloatmuIterator, which avoids creating a potentially large vector.
66116
(isfinite(start) && isfinite(stop)) || throw(ArgumentError("parameters must be finite"))
67117

68118
normal_height = 0.04*(convert(Float64,stop)-convert(Float64,start))
69119
subnormal_height = .8*normal_height
70120
plt.axis("off")
71-
fig=plot([start,stop],[0,0],"k-",color="black")
121+
fig=plot([start,stop],[0,0],"k-")
72122
for v in FloatmuIterator(start,stop)
73123
if issubnormal(v)
74124
if ticks
75-
plot([v,v],[-subnormal_height,subnormal_height],"k-",color=fpcolorsub)
125+
plot([v,v],[-subnormal_height,subnormal_height],"-",color=fpcolorsub)
76126
text(v,-normal_height,string(v),fontsize=8,ha="center",va="top",
77127
rotation=90,color=fpcolorsub)
78128
else
79129
plot(v,0,marker=".",color=fpcolorsub)
80130
end
81131
else
82132
if ticks
83-
plot([v,v],[-normal_height,normal_height],"k-",color=fpcolornorm)
133+
plot([v,v],[-normal_height,normal_height],"-",color=fpcolornorm)
84134
if v == 0.0
85135
text(0,-1.1*normal_height,L"\pm 0",fontsize=8,ha="center",va="top",
86136
rotation=90,color=fpcolornorm)
@@ -102,12 +152,43 @@ function real_line(::Type{Floatmu{szE,szf}};
102152
posInf = nextfloat(Floatmu{szE+1,szf}(floatmax(Floatmu{szE,szf})))
103153
negInf = prevfloat(Floatmu{szE+1,szf}(-floatmax(Floatmu{szE,szf})))
104154
fig = real_line(-floatmax(Floatmu{szE,szf}),floatmax(Floatmu{szE,szf}),ticks=ticks,fpcolorsub=fpcolorsub,fpcolornorm=fpcolornorm)
105-
plot([negInf,posInf],[0,0],"k-",color="black")
155+
plot([negInf,posInf],[0,0],"-",color="black")
106156
plot(negInf,0,marker="o",color=fpcolorinf)
107157
text(negInf,.02,L"-\infty",ha="center",va="bottom",fontsize=8,color=fpcolorinf)
108158
plot(posInf,0,marker="o",color=fpcolorinf)
109159
text(posInf,.02,L"\infty",ha="center",va="bottom",fontsize=8,color=fpcolorinf)
110160
return fig
111161
end
112162

163+
164+
165+
"""
166+
bits_histogram(T::Vector{Floatmu{szE,szf}};
167+
signcolor = "magenta",
168+
expcolor = "darkolivegreen",
169+
fraccolor = "blue") where {szE,szf}
170+
171+
Draw an histogram of the probability of each bit of the representation of a float
172+
to be `1` in the sample `T`.
173+
"""
174+
function bits_histogram(T::Vector{Floatmu{szE,szf}};
175+
signcolor = "magenta",
176+
expcolor = "darkolivegreen",
177+
fraccolor = "blue") where {szE,szf}
178+
occurs = vertical_popcount(T)
179+
floatsz = length(occurs)
180+
occurs = 100*(occurs ./ length(T))
181+
plt.bar(0,occurs[floatsz],color=signcolor)
182+
plt.bar(1:szE,occurs[(floatsz-1):-1:(floatsz-szE)],color=expcolor)
183+
plt.bar((szE+1):(floatsz-1),occurs[(floatsz-szE-1):-1:1],color=fraccolor)
184+
plt.yticks(0:10:100,[string(i) for i in 0.0:0.1:1.0])
185+
ticks = [collect(0:10:(floatsz-1));floatsz-1]
186+
# plt.gca().invert_xaxis()
187+
plt.xticks((floatsz-1) .- ticks, map((x)->string(x),ticks))
188+
plt.xlabel("Binary representation",fontdict=Dict("size"=>20))
189+
plt.ylabel("Probability to be 1",fontdict=Dict("size"=>20))
190+
return nothing
191+
end
192+
193+
113194
end # Module

src/MFPUtils.jl

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# MFPUtils --
2+
#
3+
# Copyright 2019--2021 University of Nantes, France.
4+
#
5+
# This file is part of the MicroFloatingPoints library.
6+
#
7+
# The MicroFloatingPoints library is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU Lesser General Public License as published
9+
# by the Free Software Foundation; either version 3 of the License, or (at your
10+
# option) any later version.
11+
#
12+
# The MicroFloatingPoints library is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14+
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
# for more details.
16+
#
17+
# You should have received copies of the GNU General Public License and the
18+
# GNU Lesser General Public License along with the MicroFloatingPoints Library.
19+
# If not, see https://www.gnu.org/licenses/.
20+
21+
module MFPUtils
22+
23+
import ..MicroFloatingPoints: Floatmu
24+
25+
export vertical_popcount
26+
27+
"""
28+
vertical_popcount(T::Vector{Floatmu{szE,szf}}) where {szE,szf}
29+
30+
Return a vector `R` of size `1+szE+szf` where `R[i]` is the number of times
31+
the `i`-th bit of the values in `T` was equal to `1`.
32+
33+
For this function, the rightmost bit of the binary representation of a `Floatmu` has index `1` and not `0` as usual.
34+
35+
# Examples
36+
37+
```jldoctest
38+
julia> join(string.(reverse(vertical_popcount(Floatmu{2,2}[1.5])))) == bitstring(Floatmu{2,2}(1.5))
39+
true
40+
```
41+
Note that, in the preceding example, we have to revert the array obtained from `vertical_popcount` because the number of times bit `i` is `1` is saved at position `i`. As a consequence, the value for the rightmost bit of a `Floatmu` appears at the leftmost position of the counting array.
42+
43+
```jldoctest
44+
julia> println(vertical_popcount(Floatmu{2,2}[0.25,1.5,3.0]))
45+
[1, 2, 1, 1, 0]
46+
```
47+
"""
48+
function vertical_popcount(T::Vector{Floatmu{szE,szf}}) where {szE,szf}
49+
count = zeros(Int,1 + szE + szf)
50+
for x in T
51+
v = x.v
52+
pos = 1
53+
while v != 0
54+
count[pos] += Int(v & 1)
55+
v >>= 1
56+
pos += 1
57+
end
58+
end
59+
return count
60+
end
61+
62+
63+
end # Module

src/MicroFloatingPoints.jl

+4
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ export eligible_step
2929

3030
include("Floatmu.jl")
3131

32+
# Submodule MFPUtils
33+
include("MFPUtils.jl")
34+
3235
# Submodule MFPPlot
3336
include("MFPPlot.jl")
3437

3538
# Submodule MFPRandom
3639
include("MFPRandom.jl")
3740

41+
3842
end # module

0 commit comments

Comments
 (0)