Ever want to know how Float64 numbers are represented in the raw machine bits?
I have written a julia code to show it to you.
function DescribeFloat64(x::Float64;verbose=false)
# Local function convert binary string 2 Int64
cbs2Int64(s) = parse(Int64,"0b" * s)
# Local function vprintln
function vprintln(args...)
if verbose == true
println(args...)
end
end
# Local ALTERNATIVE significand function
function significand_alt(T::DataType,manArr::Array{Int64,1})
# Check if all the bits in MantissaArray is 0
if sum(manArr) == 0
return convert(T,0)
end
setprecision(BigFloat, 52) do
acc = BigFloat(0.0)
multiplier = BigFloat(0.5)
for k in manArr
acc += k == 1 ? multiplier : BigFloat(0.0)
multiplier /= BigFloat(2.0)
end
acc += BigFloat(1.0)
return convert(Float64,acc)
end
end
# Local variables used in this function #
local expoBiasValue = 1023
local specialflags = false # Boolean flag
local bs = bitstring(x) # Character bit string
local signbit = bs[1] == '1' ? 1 : 0 # Sign Bit Int64
local expoView = @view bs[2:12] # a View of bit stream relevant to exponent
# exponent Array{Int64,1}
local expoArray = [ k == '1' ? 1 : 0 for k in expoView ]
local expo = cbs2Int64(expoView) # exponent Int64
local mantissaView = @view bs[13:64] # a View of bit stream relevant to mantissa
# mantissa Array{Int64,1}
local mantissaArray = Int64[ k == '1' ? 1 : 0 for k in mantissaView ]
local mysignificand = string(significand(x)) # significand Float64
# Strip the negative sign if second character is a number digit
if mysignificand[1] == '-' && mysignificand[2] == '1' || mysignificand[2] == '0'
mysignificand = lstrip(mysignificand,'-')
end
# List of special Boolean flags
local INF_flag = false # Boolean flag
local NaN_flag = false # Boolean flag
local subnormal_flag = false
# End of local variables
println("------------------------------------------------------------")
println("Float64 value : ",x)
println("Raw Bitstring : ",bs,"₂")
println("======================")
println("Sign Bit : ",bs[1],"₂")
println("Sign Value : ",signbit)
println("======================")
vprintln("Expo Array is ",expoArray)
println("Exponent Bits : ",expoView,"₂")
println("Exponent raw value : ",expo)
println("Exponent normalised value : ",expo," - $(expoBiasValue) = ",expo - expoBiasValue)
println("======================")
vprintln("Typeof mantissa is ",typeof(mantissaArray))
vprintln("mantissa Array is ",mantissaArray)
println("Mantissa : I.",bs[13:64],"₂")
println("Significand : ",mysignificand)
println("======================")
##############################################
# Now check ALL conditions for special flags #
##############################################
# Step 1: Checking for INF
# If all bits in mantissa are ZERO
# and all bits in exponent are ONE
# then INF_flag is true
if sum(mantissaArray) == 0 && prod(expoArray) == 1
specialflags = true
INF_flag = true
end
# Step 2: Checking for NaN
# If some bits in mantissa are NOT ZERO
# and all bits in exponent are ONE
# then NaN_flag is true
if sum(mantissaArray) > 0 && prod(expoArray) == 1
specialflags = true
NaN_flag = true
end
# Step 2: Checking for subnormal
# If some bits in mantissa are NOT ZERO
# and all bits in exponent are ZERO
# then subnormal_flag is true
if sum(mantissaArray) > 0 && sum(expoArray) == 0
specialflags = true
subnormal_flag = true
end
print("Value is ")
if specialflags == false
println("(-1)^",signbit," * ",mysignificand," * 2^",expo - 1023)
else # specialflags == true
if INF_flag
print(signbit == 1 ? "Negative " : "Positive ")
println("INF")
end
if NaN_flag
println("NaN")
end
if subnormal_flag
println("subnormal")
end
end
println("Value is ",x)
println("------------------------------------------------------------")
end
println("Testing 1.5"); DescribeFloat64(1.5); print()
println("Testing -1.5"); DescribeFloat64(-1.5); print()
println("Testing 1.1"); DescribeFloat64(1.1); print()
println("Testing -1.1"); DescribeFloat64(-1.1); print()
println("Testing 6.02214076e23"); DescribeFloat64(6.02214076e23); print()
println("Testing 1.0/0.0 == +INF"); DescribeFloat64(1.0/0.0); print()
println("Testing -1.0/-0.0 == +INF"); DescribeFloat64(-1.0/-0.0); print()
println("Testing -1.0/0.0 == -INF"); DescribeFloat64(-1.0/0.0); print()
println("Testing 1.0/-0.0 == -INF"); DescribeFloat64(1.0/-0.0); print()
println("Testing 0.0/0.0 == NaN"); DescribeFloat64(0.0/0.0); print()
println("Testing 0.0 == normal Zero"); DescribeFloat64(0.0); print()
println("Testing -0.0 == sign Zero"); DescribeFloat64(-0.0); print()
println("Testing 5.0e-324 == subnormal"); DescribeFloat64(5.0e-324); print()
println("Testing floatmin(Float64) == 2.2250738585072014e-308"); DescribeFloat64(2.2250738585072014e-308); print()
Here is a sample usage
julia> DescribeFloat64(-123.456789)
------------------------------------------------------------
Float64 value : -123.456789
Raw Bitstring : 1100000001011110110111010011110000000111111011100000101100001011₂
======================
Sign Bit : 1₂
Sign Value : 1
======================
Exponent Bits : 10000000101₂
Exponent raw value : 1029
Exponent normalised value : 1029 - 1023 = 6
======================
Mantissa : I.1110110111010011110000000111111011100000101100001011₂
Significand : 1.929012328125
======================
Value is (-1)^1 * 1.929012328125 * 2^6
Value is -123.456789
------------------------------------------------------------
Enjoy.