I opened the Julia REPL for the first time today. I have a 32-bit installation of Julia and 64-bit installation of Windows. The default integer type is Int32 and the default floating point type is Float64.
#these throw type assertion errors
(1 + 2)::Int64
(1.0 + 2.0)::Float32
#these work
(1 + 2)::Int32
(1.0 + 2.0)::Float64
Why is the default for integers 32-bit and the default for floating points 64-bit on my system?
Floating-point register sizes have nothing to do with your architecture word size – 64-bit floating-point registers have been available on 32-bit systems since the 8087. See this recent julia-users discussion on the subject: https://groups.google.com/forum/#!topic/julia-users/1tDvMbfCUEE.
Related
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
I am running Julia 1.0.2 under Windows 8.1.
The following leads me to believe Julia treats my machine in "little-endian" fashion:
julia> VERSION
v"1.0.2"
julia> ENDIAN_BOM
0x04030201
help?> ENDIAN_BOM
search: ENDIAN_BOM
ENDIAN_BOM
The 32-bit byte-order-mark indicates the native byte order of the host machine. Little-endian
machines will contain the value 0x04030201. Big-endian machines will contain the value
0x01020304.
Based on above, the bitstring examples below make sense to me. Both have the least significant byte first, on the left, as I would expect for little-endian byte order:
julia> bitstring(1.0)
"0011111111110000000000000000000000000000000000000000000000000000"
julia> bitstring(Char(1))
"00000001000000000000000000000000"
However, the following example seems to be in big-endian order, the least significant byte is on the right:
julia> bitstring(1)
"0000000000000000000000000000000000000000000000000000000000000001"
Am I confused? Any suggestions or explanations?
bitstring cares about host byte order. In other words,
julia> bitstring(1)
"0000000000000000000000000000000000000000000000000000000000000001"
is machine-independent, but
julia> bitstring(hton(1))
"0000000100000000000000000000000000000000000000000000000000000000"
reflects your arch. Insert hton and ntoh if you parse packets.
This is because bitstring is most used for reality-checking code that uses flags, and << et al operate on host byte order.
In your question there are two separate issues.
Char representation is a custom design decision in Julia; the approach is that UTF-8 representation of a character is filled with 0s on the right side to get 4 bytes (UInt32); you can see how the convesion happens e.g. in Char(u::UInt32) method definition.
For 1.0 and 1 you can see what are their little and big endian representations using htol and hton functions and you get:
julia> bitstring(htol(1))
"0000000000000000000000000000000000000000000000000000000000000001"
julia> bitstring(hton(1))
"0000000100000000000000000000000000000000000000000000000000000000"
julia> bitstring(htol(1.0))
"0011111111110000000000000000000000000000000000000000000000000000"
julia> bitstring(hton(1.0))
"0000000000000000000000000000000000000000000000001111000000111111"
and all is consistent.
EDIT: see the explanation in the other answer what bitstring exactly does as it is relevant.
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.
So far I learned that a processor has registers, for 32 bit processor
they are 32 bits, for 64 bit they are 64 bits. So can someone explain
what happens if I give to the processor a larger value than its register
size? How is the calculation performed?
It depends.
Assuming x86 for the sake of discussion, 64-bit integers can still be handled "natively" on a 32-bit architecture. In this case, the program often uses a pair of 32-bit registers to hold the 64-bit value. For example, the value 0xDEADBEEF2B84F00D might be stored in the EDX:EAX register pair:
eax = 0x2B84F00D
edx = 0xDEADBEEF
The CPU actually expects 64-bit numbers in this format in some cases (IDIV, for example).
Math operations are done in multiple instructions. For example, a 64-bit add on a 32-bit x86 CPU is done with an add of the lower DWORDs, and then an adc of the upper DWORDs, which takes into account the carry flag from the first addition.
For even bigger integers, an arbitrary-precision arithmetic (or "big int") library is used. Here, a dynamically-sized array of bytes is used to represent the integer, with additional information (like the number of bits used). GMP is a popular choice.
Mathematical operations on big integers are done iteratively, probably in native word-size values at-a-time. For the gory details, I suggest you have a look through the source code of one of these open-source libraries.
The key to all of this, is that numeric operations are carried out in manageable pieces, and combined to produce the final result.
I have a strange floating-point problem.
Background:
I am implementing a double-precision (64-bit) IEEE 754 floating-point library for an 8-bit processor with a large integer arithmetic co-processor. To test this library, I am comparing the values returned by my code against the values returned by Intel's floating-point instructions. These don't always agree, because Intel's Floating-Point Unit stores values internally in an 80-bit format, with a 64-bit mantissa.
Example (all in hex):
X = 4C816EFD0D3EC47E:
biased exponent = 4C8 (true exponent = 1C9), mantissa = 116EFD0D3EC47E
Y = 449F20CDC8A5D665:
biased exponent = 449 (true exponent = 14A), mantissa = 1F20CDC8A5D665
Calculate X * Y
The product of the mantissas is 10F5643E3730A17FF62E39D6CDB0, which when rounded to 53 (decimal) bits is 10F5643E3730A1 (because the top bit of 7FF62E39D6CDB0 is zero). So the correct mantissa in the result is 10F5643E3730A1.
But if the computation is carried out with a 64-bit mantissa, 10F5643E3730A17FF62E39D6CDB0 is rounded up to 10F5643E3730A1800, which when rounded again to 53 bits becomes 10F5643E3730A2. The least significant digit has changed from 1 to 2.
To sum up: my library returns the correct mantissa 10F5643E3730A1, but the Intel hardware returns (correctly) 10F5643E3730A2, because of its internal 64-bit mantissa.
The problem:
Now, here's what I don't understand: sometimes the Intel hardware returns 10F5643E3730A1 in the mantissa! I have two programs, a Windows console program and a Windows GUI program, both built by Qt using g++ 4.5.2. The console program returns 10F5643E3730A2, as expected, but the GUI program returns 10F5643E3730A1. They are using the same library function, which has the three instructions:
fldl -0x18(%ebp)
fmull -0x10(%ebp)
fstpl 0x4(%esp)
And these three instructions compute a different result in the two programs. (I have stepped through them both in the debugger.) It seems to me that this might be something that Qt does to configure the FPU in its GUI startup code, but I can't find any documentation about this. Does anybody have any idea what's happening here?
The instructions stream of and inputs to a function do not uniquely determine its execution. You must also consider the environment that is already established in the processor at the time of its execution.
If you inspect the x87 control word, you will find that it is set in two different states, corresponding to your two observed behaviors. In one, the precision control [bits 9:8] has been set to 10b (53 bits). In the other, it is set to 11b (64 bits).
As to exactly what is establishing the non-default state, it could be anything that happens in that thread prior to execution of your code. Any libraries that are pulled in are likely suspects. If you want to do some archaeology, the smoking gun is typically the fldcw instruction (though the control word can also be written to by fldenv, frstor, and finit.
normally it's a compiler setting. Check for example the following page for Visual C++:
http://msdn.microsoft.com/en-us/library/aa289157%28v=vs.71%29.aspx
or this document for intel:
http://cache-www.intel.com/cd/00/00/34/76/347605_347605.pdf
Especially the intel document mentions some flags inside the processor that determine the behavior of the FPU instructions. This explains why the same code behaves differently in 2 programs (one sets the flags different to the other).