Message Boards Message Boards

1
|
5267 Views
|
7 Replies
|
7 Total Likes
View groups...
Share
Share this post:

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

Posted 5 years ago

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

POSTED BY: Eduardo Mendes
7 Replies

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

POSTED BY: Daniel Lichtblau
Posted 5 years 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?

POSTED BY: Eduardo Mendes

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 BY: Daniel Lichtblau
Posted 5 years 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.

POSTED BY: Eduardo Mendes

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

POSTED BY: Daniel Lichtblau
Posted 5 years ago

Many thanks.

POSTED BY: Eduardo Mendes

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 *)
POSTED BY: Daniel Lichtblau
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