I have written a Module that takes a real number and returns the IEEE 754 floating point binary equivalent. It works fine for values above |1|, but I cannot get it to work for inputs less than |1|.
toBin[input_(*takes as input a decimal-
based real to be converted to IEEE754 floating-point binary*),
precision_(*either single for 32-bit or double for 64-bit*)] :=
Module[
{signbit, expobit, mantibit, addexpo, intbin, fractbin, joint,
mantissa, floatdist, exponent, binary, bitcount},
signbit = {If[Positive[input], 0, 1]};
If[precision == single, expobit = 8; mantibit = 23; addexpo = 127;
bitcount = 32, expobit = 11; mantibit = 52; addexpo = 1023;
bitcount = 64, expobit = 11; mantibit = 52; addexpo = 1023;
bitcount = 64];
intbin = IntegerDigits[IntegerPart[input], 2];
fractbin =
Drop[RealDigits[FractionalPart[input], 2,
mantibit - Length[intbin] + 2], -1] // Flatten;
joint = Join[intbin, fractbin];
floatdist = Length[intbin] - FirstPosition[joint, 1];
exponent =
PadLeft[IntegerDigits[floatdist + addexpo, 2] // Flatten, expobit];
mantissa = PadRight[Drop[joint, FirstPosition[joint, 1]], mantibit];
binary[input] = Join[signbit, exponent, mantissa] // Flatten // Row;
Return[binary[input]]]
My issue is that my "mantissa" code is not correctly dropping the first digits up to and including the first "1" in "joint" ("joint" is effectively the unformatted mantissa). e.g., for toBin[0.00035647,double], changing my return statement to output "joint" and then applying Row to that output, I get
Row[{0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 1, 0, 1, 1, 0, 0}]
which agrees with the mantissa for 0.00035647 found on baseconvert.com "0111010111001001001011111101111101000000110000101100" except for the digits including, and to the left of, the leading 1, which should be dropped for the mantissa. However when I run my module the mantissa I get is
Row[{0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 1, 0, 1, 1, 0}]
i.e. the mantissa removes the leading 1 digit but not the 0 to the left of it. The main issue with the code seems to be
mantissa = PadRight[Drop[joint, FirstPosition[joint, 1]], mantibit];
as, when I replace the FirstPosition[joint, 1] function with the number that it evaluates to (which is =2 for the example of 0.00035647)
mantissa = PadRight[Drop[joint, 2], mantibit]
I get the desired mantissa and, consequently, the correct IEEE754 binary.
How can I solve this so FirstPosition[joint, 1] produces the correctly formatted mantissa for inputs input<|1|? Additionally, I have been unable to code my module so that, when the input is +ve/-ve zero or +ve/-ve infinity, it automatically returns the designated standard IEEE754 binaries for them, rather than attempting to process them as any other number and returning errors?
EDIT: The above version of the module doesn't actually work correctly for input numbers input>|1| as I stated above; the same version but with fractbin defined as
fractbin =
Drop[RealDigits[FractionalPart[input], 2,
mantibit - Length[intbin] + 1, -1], -1] // Flatten;
does work. The only changes are that
mantibit - Length[intbin] + 1
rather than +2, and that RealDigits takes as optional final argument -1, i.e. the first digit listed by RealDigits is the 2^-1 digit. However this version of the code is even worse for inputs less than |1|.
In[125]:= hexstring = ResourceFunction["RealToHexString"][0.00035647]; bits = Flatten[ Map[IntegerDigits[FromDigits[#], 2, 4] &, Characters[hexstring]]]; binarystring = StringJoin[Map[ToString, bits]] Out[127]= \ "0011111100110111010111001001001011111101111101000000110000101100"
$\endgroup$