Assign atoms in the Earth to a variable in Julia - julia

In Python 3.6, the following works to assign a variable an estimate of the atoms in the Earth:
In[6]: atoms_in_earth = 10**50
In[7]: atoms_in_earth
Out[7]: 100000000000000000000000000000000000000000000000000
However, the following does not work in Julia 1.0.0:
julia> atoms_in_earth = 10^50
-5376172055173529600
julia> atoms_in_earth = BigInt(10^50)
-5376172055173529600
julia> atoms_in_earth = BigFloat(10^50)
-5.3761720551735296e+18
julia> atoms_in_earth = big(10^50)
-5376172055173529600
julia> atoms_in_earth = big"10^50"
ERROR: ArgumentError: invalid number format 10^50 for BigInt or BigFloat
Stacktrace:
[1] top-level scope at none:0
I was able to get these methods to work:
julia> atoms_in_earth = big"1_0000000000_0000000000_0000000000_0000000000_0000000000"
100000000000000000000000000000000000000000000000000
julia> float(ans)
1.0e+50
julia> atoms_in_earth = parse(BigInt, '1' * '0'^50)
100000000000000000000000000000000000000000000000000
julia> float(ans)
1.0e+50
I am hoping there is an easier way to do this in Julia.
What am I missing?

Julia uses native integers by default, and these can overflow. Python uses big integers by default (of arbitrary precision, it's size limit depend of the amount of available memory) and does not overflow (but is slower because of this).
Your first example overflows for Int64:
julia> atoms_in_earth = 10^50
-5376172055173529600
Your second, third and fourth examples, have already overflown, before you converted them to bigs:
julia> atoms_in_earth = BigInt(10^50)
-5376172055173529600
julia> atoms_in_earth = BigFloat(10^50)
-5.3761720551735296e+18
julia> atoms_in_earth = big(10^50)
-5376172055173529600
Your fifth example is not a valid big literal:
julia> atoms_in_earth = big"10^50"
ERROR: ArgumentError: invalid number format 10^50 for BigInt or BigFloat
But you can create a small number as a BigInt, in your example 10 and any further operations will be promoted to big arithmetic, form then on:
julia> x = 10
10
julia> typeof(x)
Int64
julia> x = BigInt(10)
10
julia> typeof(x)
BigInt
julia> big(10) == big"10" == big(10)
true
julia> y = x^50
100000000000000000000000000000000000000000000000000
julia> typeof(y)
BigInt
In this case 50 gets promoted to a BigInt as well, before computing x^50 and thus yielding a BigInt in the end.
julia> BigInt(10)^50 == big"10"^50 == big(10)^50
true

This works:
julia> atoms_in_earth = big"1e50"
1.0e+50
julia> typeof(ans)
BigFloat

Related

How do we represent the Python/numpy function "zeros_like" in Julia language

I am a bit new to Julia but I have some knowledge in Python. I am now learning Julia and I want to know how to represent the Python function "zeros_like" from Numpy in Julia.
The python code is below:
import numpy as np
a = [3] #vector of one number
b = np.zeros_like(a)
Base.zero function returns the zero element (the "additive identity element" in the doc) for the type of its input argument:
julia> a = [3]
1-element Array{Int64,1}:
3
julia> zero(a)
1-element Array{Int64,1}:
0
or
julia> zeros(Int, size(a))
1-element Array{Int64,1}:
0

Assign vector components to different variables in Julia

I want to assign the result of an operation to a concatenation of variables in Julia. Something similar to this (although this doesn't work):
a = zeros(5)
b = zeros(5)
a, b .= rand(10)
Is it possible? Thank you.
You are looking for "vector view concatenation". The idea here is to use SubArrays to build an Array that is actually a view into two arrays. Julia does not support this out of the box. The Julia package ChainedVectors.jl was built for this, but it is heavily outdated and only works with Julia <= 0.4.
Not everything is lost. You have two alternatives:
Use CatViews.jl
As pointed out in the comments, CatViews.jl is like ChainedVectors.jl, but works with Julia 0.6 and 0.7:
Pkg.add("CatViews")
using CatViews
a = zeros(2)
b = zeros(2)
CatView(a, b) .= rand(4)
Build your own solution
With a little work, we can get as good as
a = zeros(2)
b = zeros(2)
MyView(a, b) .= rand(4)
Julia allows you to build your own view-concatenation type. The effort required to build it scales proportional to how general you want it to be. Here is a first attempt that works with vectors:
julia> # Create a type for a view into two vectors.
julia> type MyView{T} <: AbstractVector{T}
a::Vector{T}
b:: Vector{T}
end
julia> import Base: size, getindex, setindex!
julia> # Define methods to make MyView behave properly.
julia> size(c::MyView) = size(c.a) .+ size(c.b)
julia> getindex(c::MyView, i::Int) = i <= length(c.a) ? getindex(a, i) : getindex(b, i-length(a))
julia> setindex!(c::MyView, val, i::CartesianIndex) = i[1] <= length(c.a) ? setindex!(c.a, val, i[1]) : setindex!(c.b, val, i[1]-length(a))
julia> setindex!(c::MyView, val, i::Int) = i <= length(c.a) ? setindex!(c.a, val, i) : setindex!(c.b, val, i-length(a))
julia> # Test MyView. Define two arrays and put them
julia> # into a single view.
julia> a = rand(2)
2-element Array{Float64,1}:
0.701867
0.543514
julia> b = rand(2)
2-element Array{Float64,1}:
0.00355893
0.405809
julia> MyView(a, b) .= rand(4)
4-element MyView{Float64}:
0.922896
0.969057
0.586866
0.457117
julia> # Hooray, it worked! As we see below,
julia> # the individual arrays were updated.
julia> a
2-element Array{Float64,1}:
0.922896
0.969057
julia> b
2-element Array{Float64,1}:
0.586866
0.457117
This?
a .= x[1:5]
b .= x[6:end]
You must tell Julia somehow where to split the vector.

How to port C++ union to Julia

I am trying to port some code and now I've hit a sticky bit. The original code is in C++. I need to port a union that has two 32 bit ints (in an array) and a double.
So far I have:
I1 = UInt32(56) # arbitrary integer values for example
I2 = UInt32(1045195987)
# do transforms on I1 and I2 as per the code I'm porting
A = bits(I1)
B = bits(I2)
return parse(Float64, string(A,B))
Is this the way to do it? The string operation seems expensive. Any advice appreciated.
I also come from mostly C/C++ programming, and this is what I do to handle the problem:
First, create an immutable type with two UInt32 elements:
immutable MyType
a::UInt32
b::UInt32
end
Then you can convert a vector of Float64 to that type with reinterpret.
For example:
julia> x = [1.5, 2.3]
2-element Array{Float64,1}:
1.5
2.3
julia> immutable MyType ; a::UInt32 ; b::UInt32 ; end
julia> y = reinterpret(MyType, x)
2-element Array{MyType,1}:
MyType(0x00000000,0x3ff80000)
MyType(0x66666666,0x40026666)
julia> x[1]
1.5
julia> y[1]
MyType(0x00000000,0x3ff80000)
julia> y[1].a
0x00000000
julia> y[1].b
0x3ff80000
Note: the two vectors still point to the same memory, so you can even update elements, using either type.
julia> x[1] = 10e91
1.0e92
julia> y[1].a
0xbf284e24
julia> y[1].b
0x53088ba3
julia> y[1] = MyType(1,2)
MyType(0x00000001,0x00000002)
julia> x[1]
4.2439915824e-314

Julia: Assignment in Arrays

When indexing more than one level for an array, it works fine. But when I used it to assign values, it did not. Does anyone know why A does not change below?
In [4]: A = rand(6)
Out [4]: 6-element Array{Float64,1}:
0.111552
0.155126
0.78485
0.147477
0.362078
0.959022
In [5]: A[3:5][[true,false,true]]
Out [5]: 2-element Array{Float64,1}:
0.78485
0.362078
In [6]: A[3:5][[true,false,true]] = [99, 999]
Out [6]: 2-element Array{Int64,1}:
99
999
In [7]: A
Out [7]: 6-element Array{Float64,1}:
0.111552
0.155126
0.78485
0.147477
0.362078
0.959022
This is because indexing arrays by ranges and vectors returns a new array with the output (instead of a view into the original array). Your statement is equivalent to the following:
julia> A = rand(6)
6-element Array{Float64,1}:
0.806919
0.445286
0.882625
0.556251
0.719156
0.276755
julia> B = A[3:5]
3-element Array{Float64,1}:
0.882625
0.556251
0.719156
julia> B[[true,false,true]] = [99, 999]
2-element Array{Int64,1}:
99
999
julia> A'
1x6 Array{Float64,2}:
0.806919 0.445286 0.882625 0.556251 0.719156 0.276755
julia> B'
1x3 Array{Float64,2}:
99.0 0.556251 999.0
You can actually see that this is what Julia is doing through some of its expression utilities. Note the explicit parentheses — it's calling setindex! on the result of indexing, which has made a copy. (GenSym() is an internal way of specifying a temporary variable):
julia> :(A[3:5][[true,false,true]] = [99, 999])
:((A[3:5])[[true,false,true]] = [99,999])
julia> expand(:(A[3:5][[true,false,true]] = [99, 999]))
:(begin
GenSym(0) = (top(vect))(99,999)
setindex!(getindex(A,colon(3,5)),GenSym(0),(top(vect))(true,false,true))
return GenSym(0)
end)
The goal is to eventually have all array indexing return views instead of copies, but that's still a work-in-progress.

Julia: check whether array entry is undef

What is the best way in Julia to check whether an array entry is #undef?
Example:
julia> a = Array(Vector,2)
julia> isdefined(a[1]) # fails
julia> isempty(a[1]) # fails
You can push the access into isdefined by using isdefined(a, 1) instead of isdefined(a[1]):
julia> a = Array(Vector,2);
julia> a[2] = {10}
1-element Array{Any,1}:
10
julia> a
2-element Array{Array{T,1},1}:
#undef
{10}
julia> isdefined(a[1])
ERROR: access to undefined reference
in getindex at array.jl:246
julia> isdefined(a, 1)
false
julia> isdefined(a, 2)
true

Resources