Message Boards Message Boards

GROUPS:

[✓] Get hexadecimal representation for a float as a string?

Posted 2 months ago
388 Views
|
7 Replies
|
7 Total Likes
|

Hello I wonder how I could use Mathematica commands to do the following:

An irrational number, ir, (a huge expression as a result of iterating a discrete map) is converted to single precision (Real16) and then to hexadecimal as a string. Example single(ir)=0.25=3e800000 (using matlab).

I know single precision is not available on WM 11.3 but Real32, Real64 and Real128 are. As for the hexadecimal representation I have to confess that I could not figure out how to do it even considering, for instance, Real32.

Your help is much appreciated.

Many thanks

Ed

7 Replies

Would BaseForm[number,16] suffice? If not, please give specifics for the hex format required.

Posted 2 months ago

Many thanks. BaseForm[0.25,16]=0.4_16 and what I need as output is 3E800000 (note that the number of digits also counts).

Example (matlab)

format hex;single(0.25)

ans =

single

3e800000

end

format hex;double(0.25)

ans =

3fd0000000000000

As far as I know there is no Real16 (single) available in Mathematica. Could it be implemented?

I'll start with the assumption that a given nonzero number is a machine double, and we want to show the hex string for either 32 or 64 bit format. We give as parameters the exponent field size and the total number of hex digits for the result.

toHex[n_Real, esize_Integer, hlen_Integer] /; 
  Precision[n] === MachinePrecision && n != 0 := Module[
  {mant, exp, sgn, bits, hexdigits, rule},
  {mant, exp} = RealDigits[n, 2];
  mant = Rest[mant];
  sgn = If[n > 0, {0}, {1}];
  exp = IntegerDigits[exp + 2^(esize - 1) - 2, 2, esize];
  bits = PadRight[Flatten[{sgn, exp, mant}], 64];
  hexdigits = Take[IntegerDigits[FromDigits[bits, 2], 16, 16], hlen];
  rule = Thread[Range[10, 15] -> Characters["abcdef"]];
  Apply[StringJoin, Map[ToString, hexdigits /. rule]]
  ]

In the examples, 32 bit floats means 8 hex digits total, and the standard exponent width is 8 bits.

toHex[.25, 8, 8]

(* Out[174]= "3e800000" *)

For 64 bit floats the exponent field is 11 bits.

toHex[.25, 11, 16]

(* Out[175]= "3fd0000000000000" *)

I will add the disclaimer that, unless one is a good speller, it might be unwise even to attempt to hex a decimal...

Posted 2 months ago

Thank you ever so much. Although I believe function toHex is exactly what I need, I wonder whether you could help me further. a) The hex number just below "3e800000" is "3e7fffff" and just above "3e800001", right? (Considering 32-bit floats). b) I also need to go back from hex to decimal taking into account the precision.

The values you give in (a) both look correct to me.

Posted 2 months ago

Many thanks.

Not yet fully tested, but this should do the inverse computation.

FromHexadecimalString[ss_String] := 
 FromHexadecimalString[ss, {11, MachinePrecision}]

FromHexadecimalString[ss_String, {esize_Integer, prec_}] /; 
  esize > 0 && N[prec] > 0 := Module[
   {hexdigits = Characters[ss], bits, rule, sgn, exp, mant},
   rule = Thread[Characters["abcdef"] -> Range[10, 15]];
   hexdigits = Map[ToExpression, Characters[ss] /. rule];
   bits = Flatten[Map[IntegerDigits[#, 2, 4] &, hexdigits]];
   sgn = If[First[bits] == 0, 1, -1];
   {exp, mant} = TakeDrop[Rest[bits], esize];
   exp = FromDigits[exp, 2] - 2^(esize - 1) + 2;
   mant = Total[1/2 + mant. 2^Range[-2, -Length[mant] - 1, -1]];
   N[sgn*mant*2^exp, prec]
   ] /; Complement[Union[Characters[ss]], 
    Join[Characters["abcdef"], Map[ToString, Range[0, 9]]]] === {}

Example:

FromHexadecimalString["3fd0000000000000"]

(* Out[413]= 0.25 *)
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract