0
$\begingroup$

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|.

$\endgroup$
3
  • $\begingroup$ Is this something you coded for your own education, or is it a function you actually require for further work? If the latter, there will be ways to obtain the result using more built-in functionality. $\endgroup$ Apr 13, 2022 at 16:18
  • $\begingroup$ Hi @DanielLichtblau, yes this was more for my own education / college project. Main stipulation being that BaseForm can't be used, but I thought to try and convert decimal reals to IEEE 754. $\endgroup$
    – J0ta
    Apr 13, 2022 at 17:26
  • $\begingroup$ Okay, that's a perfectly fine project. If it's not cheating, you are welcome to look at related conversion-to-hex code. Skipping intermediate outputs, it can even be used directly (which would be cheating...) like so: 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$ Apr 13, 2022 at 17:49

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.