Julia: Is there a way to convert a number into a pointer? - pointers

As the title says, is there a way to convert a number (say a float or interger) that stores an address into a pointer?
For example, in Julia one can convert a pointer into a integer by doing:
data = [1, 2]
ptr = pointer( data ) # Has type "Ptr{Int64}"
address = UInt64( ptr ) # Has type "UInt64"
How can one reverse these steps to get back the pointer? Say:
ptr = unknownFunction(address) # Has type "Ptr{Int64}"
Alternatively, is there a way to directly change the address held by a pointer? Say one has a pointer with:
Ptr{Int64} #0x0000000036f94110
How can you modify the address it hold to another number, for example 0x000000003ffffff0.

Yes, that it possible, but only if you already know what data lies at that pointer:
julia> arr = [15, 6, 1];
julia> address = UInt(pointer(arr));
julia> unsafe_load(Ptr{Int}(address))
15
For your second question, Julia supports pointer arithmetic. Here, you can add 8 bytes to the pointer of the first element in the array:
julia> unsafe_load(Ptr{Int}(address) + 8)
6
But I would echo other people's reservations about using pointers in Julia. They are only really useful for interoperation with e.g. C, or for doing questionable low-level bithacking tricks.

Related

How convert *uint64 and *uint32 data types to the int data type?

In my case, I have 2 variables with data types as *uint64 and *uint32. I need to convert them to the int data type.
When I try to convert them with int() function, it raise such error:
Cannot convert an expression of type *uint64 to type int.
I notice that the same int() function works without any problem if data types don't have * (asterisk) character.
So my question is how correctly convert *uint64 and *uint32 data types to the int data type?!
You can't (shouldn't) convert a pointer to int, what you most likely want to do is convert the pointed value to int.
So simply dereference the pointer to get an uint64 and uint32 value, which you can convert:
var i *uint64 = new(uint64)
var j *uint32 = new(uint32)
*i = 1
*j = 2
var k, l int
k = int(*i)
l = int(*j)
fmt.Println(k, l)
This outputs (try it on the Go Playground):
1 2
Note that of course if the pointer is nil, attempting to dereference it (like *i) results in a runtime panic.
Also note that the the size (and thus the valid range) of int is platform dependent, it may be 64 and 32 bit. Thus converting any uint64 value to int may lose the upper 32 bits, and certain positive input numbers may turn into negative ones.
[H]ow correctly convert *uint64 and *uint32 data types to the int data type?!
Like this
var a = int64(123)
var pa *uint64 = &a
var i = int(uintptr(unsafe.Pointer(&a)))
But note that while this is the "most correct way" to convert a *uint64 to int but that is almost certainly not what you want to do. What you should do: Learn the language and its type system and try to understand what pointer values are.
(Note the "most correct" as there are no correct ways to do what you asked.)

Problem with asigning non-irrational values to irrational arrays using broadcast .=

Take as example following (irrational) array
a = fill(pi, 10)
When trying to assign a different value to one element, for example
a[1] .= 0.0
Following error occurs:
ERROR: MethodError: no method matching copyto!(::Irrational{:π}, ::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0},Tuple{},typeof(identity),Tuple{Int64}})
The reason for this is that the element type of a when you construct it like that is the special number typ Irrational{:π} as seen from the output:
julia> a = fill(pi, 2)
2-element Array{Irrational{:π},1}:
π
π
When you try to put another numeric type in this container (e.g. a Float64 with value 0.0 in your example) it is like trying to fit squares in circular holes -- they don't fit.
The solution is to construct the array with the desired element type to start with. For "regular" computations you probably want Float64, so you can convert pi to a float first:
julia> a = fill(float(pi), 2)
2-element Array{Float64,1}:
3.141592653589793
3.141592653589793
The two other answers suggest you to convert your pi to Float64. In Julia you do not have to do that.
v = fill!(Vector{Union{Float64,Irrational}}(undef,10), pi)
Now your vector v can store both Float64 and Irrational numbers. Note that the performance of such code will be worse than having just a Vector{Float64} but on the other hand you are not forced to loose precision (which might be desirable or not).
First of all, we use broadcast to vectorialize operation : if you want to change all the values of the array a, you write
a .= 0.0
And if you want to change only the first value, you write
a[1] = 0.0
wich gives now a different error
ERROR: MethodError: no method matching Irrational{:π}(::Float64)
The problem comes frome the type. As you can see here, https://julialang.org/blog/2017/03/piday/ irrational is some kind of weird type. Shortly, it's only used to stock some classical values ( pi, e, ...) wich can be converted to any floating type without any intermediate routine.
It's a bit strange to set an array of irrational, I think you would prefer to use Float64. If I take your original declation, write
a = fill( Float64(pi), 10 )
an then you can use
a[1] = 0.0
or
a .= 0.0

How to get the maximum value of the item of a struct when you have an array?

I have the following structure in Julia and I create an array with it.
julia> struct myStruct
a::Int
b::Int
c::String
end
julia> myArray = myStruct.(1:10,11:20,"ABC")
10-element Array{myStruct,1}:
myStruct(1, 11, "ABC")
myStruct(2, 12, "ABC")
myStruct(3, 13, "ABC")
myStruct(4, 14, "ABC")
myStruct(5, 15, "ABC")
myStruct(6, 16, "ABC")
myStruct(7, 17, "ABC")
myStruct(8, 18, "ABC")
myStruct(9, 19, "ABC")
myStruct(10, 20, "ABC")
What shall I do in Julia to get the maximum value of a?
Is it recommended to first getting a 2 column array with the first two values of the struct and then use findmax(my2colArray[:,1]) to find the maximum value?
I have three questions to understand how shall I do this:
If getting the array first is needed, how do I get efficiently that 2 column array?
If it is not needed, how would I get the maximum value of a directly from the array of structs?
The string will contain a maximum of 50 characters, and they will be ASCII (no UTF-8). Shall I fix the length of the string somehow to improve performance?
You can use the maximum function. maximum also takes a function, which you, in this case, can use to sort by the a field:
julia> struct myStruct
a::Int
b::Int
c::String
end
julia> myArray = myStruct.(21:30,11:20,"ABC");
julia> val = maximum(x -> x.a, myArray)
30
(Slightly modified your example to make the maximum value and the index different).
The easiest way to get the max value of a is, as #fredrikekre writes:
maxval = maximum(x->x.a, arr)
Unfortunately, this does not give you the index of that value, which you also asked for in a comment.
Ideally, you could use argmax or findmax instead:
(maxval, maxind) = findmax(x->x.a, arr) # <= This does not work!!
Currently, at version 1.2 of Julia, this does not work.
There may be some other clever solution, but my advice is to just write a loop yourself, it's easy and educational!
To address your questions:
0: (This was not a question) Remember to always name your types with UpperCamelCase: so MyStruct, not myStruct.
No, you don't need this, and it's not a good solution. (Also I don't know why you want a 2-column vector, when you only are looking for the max of a). But if you really want it anyway:
v = getproperty.(x, [:a :b])
For max value, see the answer by #fredrikekre, for max index see below.
No, I don't think so.
Write your own loop to get the max index and value. It's easy and fun, and you learn to write your own fast Julia code:
function find_amax(arr::AbstractArray{MyStruct})
isempty(arr) && ArgumentError("reducing over an empty collection is not allowed")
maxind, maxval = firstindex(arr), first(arr).a
for (i, x) in enumerate(arr)
if x.a > maxval
maxind, maxval = i, x.a
end
end
return maxval, maxind
end
There is a small inefficiency in the code above, the first value and index of x is read twice. If you want even faster performance, you can figure out a way to avoid that.
As for performance, this loop is about as fast as maximum(x->x.a, arr), and more than 60x as fast as building the 2-column matrix you asked for in question 1.
The main lesson is: You don't need to look for some clever "built-in" solution that you can plug your problem into. If you cannot quickly find one, just make your own, it will most likely be faster.

Julia: Updating a Float64 within a function

I am trying to create a function to update a Float64 argument. The example below should be able to clarify what I am trying to achieve.
a=1.2
function fun!(a)
a=3.4;
end
Unfortunately, a is updated only in local scope. Is there a way to do it? I thought that passing a pointer to the function could help, but I am not sure how to do it in Julia.
You can't do this. A Float64 is not a mutable value, so you cannot mutate the value of a. You can only replace a by a separate Float64. This is what an immutable value is.
More lower level (and usually true, although there are exceptions): Float64s are represented by their actual bytes, while mutables are pointers to the actual bytes. The actual value of a mutable is its pointer. Mutating means changing values at the memory location that the pointer is pointing to, but this doesn't exist for the immutable.
To complete the answer and if you have a C/C++ background:
mutable objects are generally allocated on the heap and have stable memory addresses. They are passed by reference
immutable objects are on the stack and are passed by copy
Also, AFAIK, the ! of fun! is only a name convention to draw attention it has nothing to do with julia internals. You can write fun is you want.
Examples:
v=ones(3); # [1 1 1]
isimmutable(v) # false -> v is passed by reference
foo(v::Array{Float64}) = v .*= 2; # hence v can be modified
foo(v);
v # [2 2 2]
v=Int(1) # 1
isimmutable(v) # true -> v is passed by copy
foo(v::Int) = v *= 2 # use a local copy of v
foo(v) # returns 2, but it is a local copy
v # 1 (unmodified because we worked with a copy)
Also see FAQ
Ref{} example:
Isaiah Norton comment
foo(r::Ref{Int}) = r[] *= 2
r=Ref{Int}(1) # Base.RefValue{Int64}(1)
foo(r);
r # Base.RefValue{Int64}(2)

Having an issue with MPI_GATHER/MPI_GATHERV in F90 with derived data types

I have a task in which I will have several data types together; character, several integers, and a double precision value, which represent a solution to a problem.
At the moment, I have a "toy" F90 program, that uses MPI with random numbers and a contrived character string for each processor. I want to have a data type that has the character and the double precision random number together.
I will use MPI_REDUCE to get the minimum value for the double precision values. I will have the data type for each process brought together to the root (rank = 0) via the MPI_GATHERV function.
My goal is to match up the minimum value from the random values to the data type. That would be the final answer. I have tried all sort of ideas up to this point, but to no avail. I end up with "forrtl: severe SIGSEGV, segmentation fault occurred".
Now I have looked at several of the other postings too. For instance, I cannot use the "use mpif.h" statement on this particular system.
But, at last, here is the code:
program fredtype
implicit none
include '/opt/apps/intel15/mvapich2/2.1/include/mpif.h'
integer rank,size,ierror,tag,status(MPI_STATUS_SIZE),i,np,irank
integer blocklen(2),type(2),num,rcount(4)
double precision :: x,aout
character(len=4) :: y
type, BIND(C) :: mytype
double precision :: x,aout,test
character :: y
end type mytype
type(mytype) :: foo,foobag(4)
integer(KIND=MPI_ADDRESS_KIND) :: disp(2),base
call MPI_INIT(ierror)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror)
aout = 99999999999.99
call random_seed()
call random_number(x)
if(rank.eq.0)y="dogs"
if(rank.eq.1)y="cats"
if(rank.eq.2)y="tree"
if(rank.eq.3)y="woof"
print *,rank,x,y
call MPI_GET_ADDRESS(foo%x,disp(1),ierror)
call MPI_GET_ADDRESS(foo%y,disp(2),ierror)
base = disp(1)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror)
aout = 99999999999.99
call random_seed()
call random_number(x)
if(rank.eq.0)y="dogs"
if(rank.eq.1)y="cats"
if(rank.eq.2)y="tree"
if(rank.eq.3)y="woof"
print *,rank,x,y
call MPI_GET_ADDRESS(foo%x,disp(1),ierror)
call MPI_GET_ADDRESS(foo%y,disp(2),ierror)
base = disp(1)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror)
aout = 99999999999.99
call random_seed()
call random_number(x)
if(rank.eq.0)y="dogs"
if(rank.eq.1)y="cats"
if(rank.eq.2)y="tree"
if(rank.eq.3)y="woof"
print *,rank,x,y
call MPI_GET_ADDRESS(foo%x,disp(1),ierror)
call MPI_GET_ADDRESS(foo%y,disp(2),ierror)
base = disp(1)
disp(2) = disp(2) - base
blocklen(1) = 1
blocklen(2) = 1
type(1) = MPI_DOUBLE_PRECISION
type(2) = MPI_CHARACTER
call MPI_TYPE_CREATE_STRUCT(2,blocklen,disp,type,foo,ierror)
call MPI_TYPE_COMMIT(foo,ierror)
call MPI_REDUCE(x,aout,1,MPI_DOUBLE_PRECISION,MPI_MIN,0,MPI_COMM_WORLD,i\
error)
call MPI_GATHER(num,1,MPI_INT,rcount,1,MPI_INT,0,MPI_COMM_WORLD)
call MPI_GATHERV(foo,num,type,foobag,rcount,disp,type,0,MPI_COMM_WORLD)
if(rank.eq.0)then
print *,'fin ',aout
end if
end program fredtype
Thank you for any help.
Sincerely,
Erin
Your code is definitely too confusing for me to try to fully fix it. So let's just assume that you have your type mytype defined as follow:
type, bind(C) :: mytype
double precision :: x, aout, test
character(len=4) :: y
end type mytype
(Rk: I've add len=4 to the definition of y as it seemed to be missing from your original code. I might be wrong it that and if so, just adjust blocklen(2) in the subsequent code accordingly)
Now let's assume that you only want to transfer the x and y fields of your variables of type mytype. For this, you'll need to create an appropriated derived MPI type using first MPI_Type_create_struct() to define the basic types and their location into your structure, and then MPI_Type_create_resized() to define the true extent and lower bound of the type, including holes.
The tricky part is usually to evaluate what the lower bound and extent of your Fortran type is. Here, as you include into the fields that you transfer the first and last of them, and as you added bind(C), you can just use MPI_Type_get_extend() to get these informations. However, if you hadn't included x or y (which are first and last fields of the type) into the MPI data type, MPI_Type_get_extent() wouldn't have return what you would have needed. So I'll propose you an alternative (slightly more cumbersome) approach which will, I believe, always work:
integer :: ierror, typefoo, tmptypefoo
integer :: blocklen(2), types(2)
type(mytype) :: foobag(4)
integer(kind=MPI_ADDRESS_KIND) :: disp(2), lb, extent
call MPI_Get_address( foobag(1), lb, ierror )
call MPI_Get_address( foobag(1)%x, disp(1), ierror )
call MPI_Get_address( foobag(1)%y, disp(2), ierror )
call MPI_Get_address( foobag(2), extent, ierror )
disp(1) = MPI_Aint_diff( disp(1), lb )
disp(2) = MPI_Aint_diff( disp(2), lb )
extent = MPI_Aint_diff( extent, lb )
lb = 0
blocklen(1) = 1
blocklen(2) = 4
types(1) = MPI_DOUBLE_PRECISION
types(2) = MPI_CHARACTER
call MPI_Type_create_struct( 2, blocklen, disp, types, tmptypefoo, ierror )
call MPI_Type_create_resized( tmptypefoo, lb, extent, typefoo, ierror )
call MPI_Type_commit( typefoo, ierror )
So as you can see, lb serves as base address for the displacements into the structure, and the type extent is computed by using the relative addresses of two consecutive elements of an array of type mytype.
Then, we create an intermediary MPI data type tmptypefoo which only contains the information about the actual data we will transfer, and we extent it with information about the actual lower bound and extent of the Fortran type into typefoo. Finally, only this last one needs to be committed as only it will serve for data transfers.

Resources