In Julia: Equality of Float64 and BigFloat - julia

In the Julia 1.0.0 REPL I get the following results:
# Line 1: This make sense. I did not expect a Float64 to equal a BigFloat.
julia> 26.1 == big"26.1"
false
# Line 2: This surprised me when Line 1 is considered. Again, like Line 1, I
# did not expect a Float64 to equal an equivalent BigFloat.
julia> 26.0 == big"26.0"
true
# Line 3: This I expected based on Line 1 behavior.
julia> 26.1 - 0.1 == big"26.1" - 0.1
false
# Line 4: This surprised me based on Line 1 behavior, but it might be
# explained based on Line 2 behavior. It seems to imply that if a Float64
# can be converted to an Integer it will compare equal to an equivalent BigFloat.
julia> 26.1 - 0.1 == big"26.1" - big"0.1"
true
It seems that Julia is doing something under the hood here for equality comparisons with Float64 and BigFloat that makes lines 2 and 4 true, while lines 1 and 3 are false. Any suggestions?
The Julia doc regarding "==" does not seem to cover this kind of thing:
https://docs.julialang.org/en/v1/base/math/#Base.:==
EDIT:
Based on a helpful comment by #EPo below, it is easy to make all comparisons above come out to true. For example, Line 1 and Line 3 are true below, though they were false above:
# Line 1 is now true.
julia> 26.1 ≈ big"26.1"
true
# Line 3 is now true.
julia> 26.1 - 0.1 ≈ big"26.1" - 0.1
true

Some floating point number can be represented exactly (26.0) but not all, for instance:
julia> using Printf
julia> #printf("%.80f",26.0)
26.00000000000000000000000000000000000000000000000000000000000000000000000000000000
julia> #printf("%.80f",0.1)
0.10000000000000000555111512312578270211815834045410156250000000000000000000000000
The decimals 0.5, 0.25, 0.125 for example can be also represented exactly with the binary based floating point representation. So for instance you have:
julia> 26.125 - 0.125 == big"26.125" - 0.125
true
But 0.1 is a periodic number in the binary system, so it is rounded.
julia> bitstring(0.1)
"0011111110111001100110011001100110011001100110011001100110011010"
The last 52 bits represent the fraction in binary. (https://en.wikipedia.org/wiki/Double-precision_floating-point_format)

The reason they are not the same is because they are not the same
julia> using Printf
julia> string(BigFloat("26.1")-BigFloat("26"))
"1.000000000000000000000000000000000000000000000000000000000000000000000000000553e-01"
julia> #printf("%.17e",Float64(26.1)-Float64(26))
1.00000000000001421e-01
julia> Float64(26.1)-Float64(26) > BigFloat("26.1")-BigFloat("26")
true

Related

Julia equivalent of Python numpy "arange"

In Python, I can create an array of evenly spaced values using
xi2 = np.arange(0, np.sqrt(6), 1e-3)
How do I write this in Julia? I tried,
xi2 = range(0,sqrt(6),step=1e-3)
but this returns 0.0:0.001:2.449
The result, 0.0:0.001:2.449 is indeed a range of evenly spaced values, and can be indexed, sliced, broadcasted on, and generally used just like any other AbstractArray. For example:
julia> xi2 = range(0,sqrt(6),step=1e-3)
0.0:0.001:2.449
julia> xi2[1]
0.0
julia> xi2[100]
0.099
julia> length(xi2)
2450
julia> isa(xi2, AbstractArray)
true
julia> sin.(xi2)
2450-element Vector{Float64}:
0.0
0.0009999998333333417
0.0019999986666669333
0.002999995500002025
⋮
0.6408405168240852
0.6400725224915994
0.6393038880866445
0.6385346143778549
If for any reason you want to turn xi2 into a full Array preemptively, you can do that with collect
julia> collect(xi2)
2450-element Vector{Float64}:
0.0
0.001
0.002
0.003
⋮
2.446
2.447
2.448
2.449
which will "materialize" the range, so to speak. This uses a lot more memory than the Range though, and is less often necessary than you might expect.

Julia - console behaving differently than include("myfile.jl")

I would like to execute the following code, which works perfectly well when I type every line into my Julia console on Windows 10, but throws an error because of the mismatching type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} (my subsequent code expects Array{Float64,2}).
This is the code:
x = [0.2, 0.1, 0.2]
y = [-0.5 0.0 0.5]
fx = x * y
fy = fx'
return fx::Array{Float64,2}, fy::Array{Float64,2}
There is a TypeError, because fy seems to be of type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} instead of Array{Float64,2}.
How can I do a transpose and get a "normal" Array{Float64,2} object ?
And why does this work when I type every line into my Julia console, but does not when I run the file via include("myfile.jl") ?
Use collect to have a copy of actual data rather than a transformed view of the original (note that this rule applies to many other similar situations):
julia> x = [0.2, 0.1, 0.2];
julia> y = [-0.5 0.0 0.5];
julia> fx = x * y
3×3 Array{Float64,2}:
-0.1 0.0 0.1
-0.05 0.0 0.05
-0.1 0.0 0.1
julia> fy = fx'
3×3 LinearAlgebra.Adjoint{Float64,Array{Float64,2}}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
julia> fy = collect(fx')
3×3 Array{Float64,2}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
To get a normal Matrix{Float64} use:
fy = permutedims(fx)
or
fy = Matrix(fx')
Those two are not 100% equivalent in general as fx' is a recursive adjoint operation (conjugate transpose), while permutedims is a non-recursive transpose, but in your case they will give the same result.
What does recursive adjoint mean exactly?
recursive: the conjugate transpose is applied recursively to all entries of the array (in your case you have array of numbers and transpose of a number is the same number so this does not change anything);
adjoint: if you would have complex numbers then the operation would return their complex conjugates (in your case you have real numbers so this does not change anything);
Here is an example when both things matter:
julia> x = [[im, -im], [1-im 1+im]]
2-element Array{Array{Complex{Int64},N} where N,1}:
[0+1im, 0-1im]
[1-1im 1+1im]
julia> permutedims(x)
1×2 Array{Array{Complex{Int64},N} where N,2}:
[0+1im, 0-1im] [1-1im 1+1im]
julia> Matrix(x')
1×2 Array{AbstractArray{Complex{Int64},N} where N,2}:
[0-1im 0+1im] [1+1im; 1-1im]
However, unless you really need to you do not have to do it if you really need to get a conjugate transpose of your data. It is enough to change type assertion to
return fx::Array{Float64,2}, fy::AbstractArray{Float64,2}
or
return fx::Matrix{Float64}, fy::AbstractMatrix{Float64}
Conjugate transpose was designed to avoid unnecessary allocation of data and most of the time this will be more efficient for you (especially with large matrices).
Finally the line:
return fx::Array{Float64,2}, fy::Array{Float64,2}
throws an error also in the Julia command line (not only when run from a script).

Understanding Julia Int overflow behaviour

Coming from a Python / Matlab background, I'd like to understand better how Julia's Int64 overflow behaviour works.
From the documentation:
In Julia, exceeding the maximum representable value of a given type
results in a wraparound behavior.
julia> x = typemax(Int64)
9223372036854775807
julia> x + 1
-9223372036854775808
Now, I did some experiments with numbers obviously larger than typemax(Int64), but the behaviour I see isn't consistent with the documentation. It seems like things don't always just wrap around. Is only a single wraparound allowed?
julia> x = (10^10)^(10^10)
0
julia> x = 10^10^10^10
1 # ??
julia> x = 10^10^10^10^10
10 # I'd expect it to be 1? 1^10 == 1?
julia> x = 10^10^10^10^10^10
10000000000 # But here 10^10 == 10000000000, so now it works?
julia> typemax(Int64) > 10^19
true
julia > typemax(Int64) > -10^19
true
Can anyone shed light on the behaviour I am seeing?
EDIT:
Why does 9 overflow correctly, and 10 doesn't?
julia> 9^(10^14)
-1193713557845704703
julia> 9^(10^15)
4900281449122627585
julia> 10^(10^2)
0
julia> 10^(10^3)
0
Julia 0.5.0 (2016-09-19)
What you are seeing the result of PEMDAS order of operations, specifically the parenthesis before exponentiation portion. This effectively becomes a right-to-left solving of these expressions.
julia> 10^(10^10) #happens to overflow to 0
0
julia> 10^(10^(10^10)) # same as 10 ^ 0
1
julia> 10^(10^(10^(10^(10^10)))) # same as x = 10^(10^(10^(10^(10000000000)))) -> 10^(10^(10^(0))) -> 10^(10^(1)) -> 10^ 10
10000000000
So it's really just a matter of working through the arithmetic. Or realizing you are going to have such large operations that you start using BigInt from the outset.

How do you select a subset of an array based on a condition in Julia

How do you do simply select a subset of an array based on a condition? I know Julia doesn't use vectorization, but there must be a simple way of doing the following without an ugly looking multi-line for loop
julia> map([1,2,3,4]) do x
return (x%2==0)?x:nothing
end
4-element Array{Any,1}:
nothing
2
nothing
4
Desired output:
[2, 4]
Observed output:
[nothing, 2, nothing, 4]
You are looking for filter
http://docs.julialang.org/en/release-0.4/stdlib/collections/#Base.filter
Here is example an
filter(x->x%2==0,[1,2,3,5]) #anwers with [2]
There are element-wise operators (beginning with a "."):
julia> [1,2,3,4] % 2 .== 0
4-element BitArray{1}:
false
true
false
true
julia> x = [1,2,3,4]
4-element Array{Int64,1}:
1
2
3
4
julia> x % 2 .== 0
4-element BitArray{1}:
false
true
false
true
julia> x[x % 2 .== 0]
2-element Array{Int64,1}:
2
4
julia> x .% 2
4-element Array{Int64,1}:
1
0
1
0
You can use the find() function (or the .== syntax) to accomplish this. E.g.:
julia> x = collect(1:4)
4-element Array{Int64,1}:
1
2
3
4
julia> y = x[find(x%2.==0)]
2-element Array{Int64,1}:
2
4
julia> y = x[x%2.==0] ## more concise and slightly quicker
2-element Array{Int64,1}:
2
4
Note the .== syntax for the element-wise operation. Also, note that find() returns the indices that match the criteria. In this case, the indices matching the criteria are the same as the array elements that match the criteria. For the more general case though, we want to put the find() function in brackets to denote that we are using it to select indices from the original array x.
Update: Good point #Lutfullah Tomak about the filter() function. I believe though that find() can be quicker and more memory efficient. (though I understand that anonymous functions are supposed to get better in version 0.5 so perhaps this might change?) At least in my trial, I got:
x = collect(1:100000000);
#time y1 = filter(x->x%2==0,x);
# 9.526485 seconds (100.00 M allocations: 1.554 GB, 2.76% gc time)
#time y2 = x[find(x%2.==0)];
# 3.187476 seconds (48.85 k allocations: 1.504 GB, 4.89% gc time)
#time y3 = x[x%2.==0];
# 2.570451 seconds (57.98 k allocations: 1.131 GB, 4.17% gc time)
Update2: Good points in comments to this post that x[x%2.==0] is faster than x[find(x%2.==0)].
Another updated version:
v[v .% 2 .== 0]
Probably, for the newer versions of Julia, one needs to add broadcasting dot before both % and ==

Python .1 - .1 = extremely small number w/negative exponent?

This has got to be a well-traveled gotcha of some sort. Define the following function foo():
>>> def foo():
... x = 1
... while x != 0:
... x -= .1
... if x < 0:
... x = 0
... print x
So of course, when we call the function, we get exactly what we expect to get.
>>> foo()
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
1.38777878078e-16 # O_o
0
So, I know that math with integers vs. floating point numbers can get a little weird. Just typing 3 - 2.9 yields such an answer:
>>> 3 - 2.9
0.10000000000000009
So, in fairness -- this is not causing an issue in the script I'm mucking about with. But surely this creeps up and bites people who would actually be affected by values as astronomically small as 1.38777878078e-16. And in order to prevent there from ever being an issue because of the strangely small number, I've got this gem sitting at the bottom of my controller du jour:
if (x < .1 and x > 0) or x < 0:
x = 0
That can't be the solution... unless it totally is. So... is it? If not, what's the trick here?
This can certainly "creep up and bite people", generally when they try to compare floats:
>>> a = 1 / 10
>>> b = 0.6 - 0.5
>>> a == b
False
Therefore it is common to compare floats using a tolerance:
>>> tolerance = 0.000001
>>> abs(a - b) < tolerance
True
This program:
def foo():
x = 1
while x != 0:
x -= .1
if x < 0:
x = 0
print '%.20f' % x
foo()
prints out this:
0.90000000000000002220
0.80000000000000004441
0.70000000000000006661
0.60000000000000008882
0.50000000000000011102
0.40000000000000013323
0.30000000000000015543
0.20000000000000014988
0.10000000000000014433
0.00000000000000013878
0.00000000000000000000
You were not printing the numbers out with enough precision to see what was actually going on. Compare this with the output of print '%.20f' % x when you explicitly set x to 0.9 and 0.8 and so forth. You may want to pay particular attention to the result for 0.5.
You miss the point - that isn't something you want to have a workaround for. Just trust VM, and assume, that it does all the computations as they should be done.
What you want to do, is to format your number. Spot the difference between value, and its representation.
>>> x = 0.9
>>> while x>0.1:
... x -= 0.1
...
>>> x
1.3877787807814457e-16
>>> "{:.2f}".format(x)
'0.00'
Here you have example of showing you value with 2 decimal points. More on formatting (number formatting too) you'll find HERE

Resources