Is Sys.WORD_SIZE guaranteed to match the default integer size? - julia

The section of the Julia documentation for Integers describes the default type (size) of an integer [with Int being an alias for either Int32 or Int64]:
The default type for an integer literal depends on whether the target system has a 32-bit architecture or a 64-bit architecture
There is also a definition of the Sys.WORD_SIZE variable:
The Julia internal variable Sys.WORD_SIZE indicates whether the target system is 32-bit or 64-bit
However, the variation in terminology (the first refers to "architecture" while the second doesn't) allows for some ambiguity regarding "system" vs. "architecture".
Are there any circumstances where the default size of an integer and Sys.WORD_SIZE would not match?

No, Sys.WORD_SIZE is defined in terms of the size of Int. See https://github.com/JuliaLang/julia/blob/master/base/sysinfo.jl.
"""
Sys.WORD_SIZE::Int
Standard word size on the current machine, in bits.
"""
const WORD_SIZE = Core.sizeof(Int) * 8

Related

Is it possible to declare Ada range with unlimited upper bound?

I would like to declare a speed range for a record type in Ada. The following won't work, but is there a way to make it work?
--Speed in knots, range 0 to unlimited
Speed : float Range 0.0 .. unlimited ;
I just want a zero positive value for this number...
You can't -- but since Speed is of type Float, its value can't exceed Float'Last anyway.
Speed : Float range 0.0 .. Float'Last;
(You'll likely want to declare an explicit type or subtype.)
Just for completeness, you can also define your own basic float types rather than use one called Float which may or may not have the range you require.
For example, Float is defined somewhere in the compiler or RTS (Runtime System) sources, probably as type Float is digits 7; alongside type Long_Float is digits 15;, giving you 7 and 15 digits precision respectively.
You can define yours likewise to satisfy the precision and range your application requires. The philosophy is, state what you need (in range and precision), and let the compiler satisfy it most efficiently. This is programming in the problem domain, stating what you want - rather than in the solution domain, binding your program to what a specific machine or compiler supports.
The compiler will either use the next highest precision native float (usually IEEE 32-bit or 64-bit floats) or complain that it can't do that
(e.g. if you declare
type Extra_Long_Float is digits 33 range 0.0 .. Long_Float'Last * Long_Float'Last;
your compiler may complain if it doesn't support 128 bit floats.
Unlimited isn't possible. It would require unlimited memory. I'm not aware of any platform that has that. It's possible to write a package that provides rational numbers as big as the available memory can handle (see PragmARC.Rational_Numbers in the PragmAda Reusable Components for an example), but that's probably not what you're interested in. You can declare your own type with the maximal precision supported by your compiler:
type Speed_Value_Base is digits System.Max_Digits;
subtype Speed_Value is Speed_Value_Base range 0.0 .. Speed_Value_Base'Last;
Speed : Speed_Value;
which is probably what you're after.

How can I increment an access type as if it were a C pointer?

How to increment an address of access type like a pointer in C? I am new to Ada...
procedure main is
type myarr is array(1..5)of integer; --creating array of 5 integer.
myarr_var:aliased myarr:=(2,5,7,9,0); --setting 5 values
type my_access is access all myarr; --creating access type (pointer)
var:my_access:=myarr_var'access; --holding address of 5 integer
begin;
-- since var holds the address of myarr_var now i want to increment
-- the address by adding 1 to print next value (5) as we do in c?
put((var+1).all); --???
-- i know this is bad but how to increment its base address of
-- var(pointer) so that it will point to next element 5?
end main;
Instantiate Interfaces.C.Pointers to do C-style pointer arithmetic in Ada.
Best explained by example:
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C.Pointers;
procedure Access_Pointer_Arithmetic is
type Myarr_Indices is range 1 .. 5;
type Myarr is array (Myarr_Indices range <>) of aliased Integer;
Myarr_Terminator : constant Integer := 0;
package Myarr_Pointer_Arithmetic is new Interfaces.C.Pointers
(Myarr_Indices, Integer, Myarr, Myarr_Terminator);
use Myarr_Pointer_Arithmetic;
Myarr_Var : aliased Myarr := (2, 5, 7, 9, 0);
Var : Myarr_Pointer_Arithmetic.Pointer :=
Myarr_Var(Myarr_Var'First)'access;
begin
Put_Line(Integer'Image(Var.all));
Increment(Var);
Put_Line(Integer'Image(Var.all));
Increment(Var);
Put_Line(Integer'Image(Var.all));
Increment(Var);
Put_Line(Integer'Image(Var.all));
Var := Var - 2;
Put_Line(Integer'Image(Var.all));
end Access_Pointer_Arithmetic;
Running it:
C:\Ada\Sandbox\access_pointer_arithmetic
2
5
7
9
5
This package provides single increment/decrement, addition and subtraction of ptrdiff_t, and both terminator-specified and fixed length element array retrieval.
(Mind running off the end of the array... :-)
UPDATE : I just found out that there's a standard package Interfaces.C.Pointers that directly supports C-style pointer arithmetic, and now I see that Marc C.'s accepted answer covers its usage. You can probably ignore my answer, which discusses how you might do pointer arithmetic in Ada if Interfaces.C.Pointers didn't exist (which, in earlier versions of the language, it doesn't).
If you really want to do C-style pointer arithmetic on Ada access types, you can use the generic package System.Address_To_Access_Conversions to convert an object pointer type to System.Address, and the System.Storage_Elements package to perform C-like arithmetic on System.Address values.
Note that the target object type is a parameter to the System.Address_To_Access_Conversions generic package. The package itself defines the access type. You can't define your own access type and use it (at least not directly).
Keep in mind that C pointer arithmetic is defined in units of the size of the pointed-to object. So given:
int arr[10];
int *ptr = &arr[0];
the pointer value ptr + 3 points to arr[3], which is three int-sized chunks of memory past the location to which ptr points not necessarily three bytes. The "+" and "-" operators in System.Storage_Elements work with offsets in storage elements (which are very likely equivalent to C's "bytes").
So if you have an Ada pointer, um, I mean access value, that refers to an element of an array of Integers, then advancing to the next element of that array requires:
Using System.Address_To_Access_Conversions to convert the access type to System.Address;
Using the overloaded "+" operator in System.Storage_Elements to add the size of an Integer in bytes (Integer'Max_Size_In_Storage_Elements) to the System.Address value; and
Using System.Address_To_Access_Conversions again to convert the System.Address value back to your access type.
An alternative might be to write C code to do whatever pointer arithmetic you need, and use Interfaces.C to call that code from your Ada program.
But it's very likely that you don't need to do pointer arithmetic in Ada. C has pointer arithmetic in the core language; it even defines array indexing in terms of pointer arithmetic. Ada does not. There's rarely a good reason to perform pointer arithmetic in Ada. Just let arrays be arrays, and let the compiler figure out how to generate the best code to access their elements. (That code will likely involve pointer arithmetic on the CPU instruction level.)

How to convert a Julia Bool Array to Fortran Logical Array

How can I convert a Julia Int/Bool Array/Vector to a Fortran LOGICAL array for use within Julia's ccall?
I tried passing it as Array{Bool} in https://gist.github.com/axsk/28f297e2207365a7f4e8/, but the code is not working correctly and I am quite confident the problem is the Bool-Logical conversion.
I don't know too much about calling Fortran code, but according to this
The Fortran standard does not specify how variables of LOGICAL type
are represented, beyond requiring that LOGICAL variables of default
kind have the same storage size as default INTEGER and REAL variables.
The GNU Fortran internal representation is as follows.
A LOGICAL(KIND=N) variable is represented as an INTEGER(KIND=N)
variable, however, with only two permissible values: 1 for .TRUE. and
0 for .FALSE.. Any other integer value results in undefined behavior.
So I'd do something like the following
julia_array = rand(Bool, 1:10)
fort_array = Int[x?1:0 for x in julia_array]
Then use fort_array as the input. Which Fortran compiler are you using?
EDIT: It turns out the Julia developers already define a type that will work with the linked BLAS/LAPACK, Base.BLAS.BlasInt, that will use the correct Int variant for the system.
As iaindunning posted before, Fortran represents Logical variables as Integers.
Unfortunately the representation of the type Integer varies from platform to platform.
While I had success using Int on Windows and Cint on Linux/MacOS, in the end I used BlasInt, which adopts depending on the platform.

Nested as_type Casting

When I nest OpenCL's as_type operators, I get some strange errors. For example, this line works:
a = as_uint(NAN)&4290772991;
But these lines do not work:
a = as_float(as_uint(NAN)&4290772991);
a = as_uint(as_float(as_uint(NAN)&4290772991));
The error reads:
invalid reinterpretation: sizes of 'float' and 'long' must match
This error message is confusing, because it seems like no long is created by this code. All values here appear to be 32-bits, so it should be possible to reinterpret cast anything.
So why is this error happening?
In C99, undecorated decimal constants are assumed to be signed integers and the compiler will automagically define the constant as the smallest signed integer type which can hold the value using the progression int, then long int, then finally unsigned long int.
The smallest signed integer type which can hold 4290772991 is a 64 bit signed type (because of the sign bit requirement). Thus, the as_type calls you have where the reinterpret type is a 32 bit type fail because of the size mismatch between the 64 bit long int the compiler selects for your constant and the target float type.
You should be able to get around the problem by changing 4290772991 to 4290772991u. The suffix will explicitly denote the value as unsigned, and the compiler should select a 32 bit unsigned integer. Alternatively, you could also use 0xFFBFFFFF - there are different rules for hexadecimal constants and it should be assigned a type from the progression int, then unsigned int, then long int, then finally unsigned long int.

How many bytes does a derived type (in Fortran) occupy? Are the locations contiguous? And a pointer to a derived type?

I could not find this anywhere, and even if it could be trivial I wanna be sure I have well understood. I have 4 questions (strictly related):
1)If I define a derived type in fortran like this
TYPE :: node
INTEGER :: int
REAL :: REALfirst
REAL :: REALsecond
END TYPE
TYPE(node) :: var
allocate(var)
After the above allocation it occupies 4 byte for the integer and other 8 for the 2 single precision reals, for a total of 12 bytes. Are they located continuously in memory? And how does the computer store the information about the type of variables?I guess it needs some extra memory for saving that.
2)if in the example above instead of
TYPE(node) :: var
i would have written:
TYPE(node),POINTER :: var
I guess that if I compiled a 32 bit executable the ALLOCATE statement would allocate the same amount of memory as in the example above. Is it correct?
3)Now lets suppose i declare the type
TYPE :: node
INTEGER :: int
TYPE(node), POINTER :: BEFORE
TYPE(node), POINTER :: AFTER
END TYPE
TYPE(node) :: var
allocate(var)
here (if 32-bit compiled) it would allocate 4 byte for the integer and other 8 for the 2 pointers, for a total of 12 bytes. is that correct?Again how does the computer store the information about the type of variables?
4)In the example (3) if I now write ALLOCATE(var%BEFORE), other 12 bytes are allocated for a variable with derived type node, and the 4 byte of integer type that were allocated for the pointer var%BEFORE (see example 3) are now freed, correct?
THANKS
A.
1) This is not covered by the fortran standard. real and integer do not have to be 4 bytes wide. To ensure that by specifying their precision. If you do not care about the numeric precision, but about the number of bytes, do it like this
!In Fortran 2008
use iso_fortran_env
or
!In Fortran 95
integer,parameter :: int32 = selected_int_kind(9)
integer,parameter :: real32 = selected_real_kind(p=6,r=37)
and
TYPE :: node
INTEGER(int32) :: int
REAL(real32) :: REALfirst
REAL(real32) :: REALsecond
END TYPE
The compiler is allowed the insert any padding it wants. This is likely ta happen if you mix variables with 4, 8 or even more bytes. To suppress any padding use SEQUENCE.
2) The allocated memory would be the same. The compiler also uses some datastructure (it may be just an address, but doesn't have to) for bookkeeping.
3) The bookkeeping datastructure I reffered to is stored in the datatype. It may be just an address.
4) The pointer data structuture can be 4 bytes, but also can be more. The more important point is however, that they are not freed. You must know where to find the allocated space on the heap and you use the pointer for that. It does not matter, whether you use this pointer to allocate new data, or if you point to some existing one.
Note, that bit size of the derived type cannot change at runtime, it is fixed. Another issue are polymorphic variables, but they must be allocated dynamically for this reason.

Resources