Using Julia's range function such that the range values have the same number of significant digits

Viewed 38

Consider the following function in Julia:

points = range(0.0, 0.5, length = 100)

The output is like this : 0.0 p1 p2 ... 0.5

Now, p1, p2, etc. have different number of digits after the decimal points. What I want to do is to get an output which has a fixed number of digits after the decimal point. For example, I want to set the boundary points to 0.00000 and 0.50000 and also get points in the range each with five digits after the decimal point. I would also like to print the output to a file such that each number (including 0.0 and 0.5) has the same number of digits after the decimal point.

How to do this in Julia?

2 Answers

There are few approaches depending on what you exactly require

  • avoiding range materialization (as @Antonello suggested)
  • rounding
  • using real number arithmetic
  • using fixed floating point precision

You could do rounding but you loose precision:

julia> round.(range(0.0, 0.5, length = 10);digits=5)
10-element Vector{Float64}:
 0.0
 0.05556
 0.11111
 0.16667
 0.22222
 0.27778
 0.33333
 0.38889
 0.44444
 0.5

If you are looking for verbose output without precision loss I would recommend looking at rational numbers instead:

julia> collect(range(0//1, 1//2, length = 10))
10-element Vector{Rational{Int64}}:
 0//1
 1//18
 1//9
 1//6
 2//9
 5//18
 1//3
 7//18
 4//9
 1//2

You could also consider using fixed floating point precision by using FixedPointNumbers. Here I use 16 bits to store the floating point part of a number:

julia> range(Fixed{Int,5}(0.0),Fixed{Int,16}(0.5); length=10)
10-element LinRange{Fixed{Int128, 16}, Int64}:
 0.0,0.05556,0.11111,0.16667,0.22223,0.27777,0.33333,0.38889,0.44444,0.5

Since your goal is to have a fixed number of digits after the decimal point, this can be easily done by modifying the show method:

using Printf
Base.show(io::IO, f::Float64) = @printf(io, "%.5f", f)

Now, if you do

julia> points = range(0.0, 0.5, 100);

julia> collect(points)
100-element Vector{Float64}:
 0.00000
 0.00505
 0.01010
 0.01515
 0.02020
 0.02525
 0.03030
 ⋮
 0.46970
 0.47475
 0.47980
 0.48485
 0.48990
 0.49495
 0.50000

you get what you want printed in the REPL. You can go a head and save to a file if you want also.

open("nums.txt", "w") do f
    println.(f, collect(points))
end;

Be aware that any rounding or fixed-digit printing would loose the TwicePrecision floats that Julia's range has offered you.

Related