{"id":45321,"date":"2015-06-22T07:00:00","date_gmt":"2015-06-22T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20150622-00\/?p=45321\/"},"modified":"2019-03-13T12:16:36","modified_gmt":"2019-03-13T19:16:36","slug":"20150622-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150622-00\/?p=45321","title":{"rendered":"Reinterpreting the bits of a 64-bit integer as if they were a double-precision floating point number (and vice versa)"},"content":{"rendered":"<p>Today&#8217;s Little Program takes a 64-bit integer and reinterprets its physical representation as a double-precision floating point number. <\/p>\n<pre>\nusing System;\n\nclass Program\n{\n static double ReinterpretAsDouble(long longValue)\n {\n  return BitConverter.ToDouble(BitConverter.GetBytes(longValue), 0);\n }\n\n static long ReinterpretAsLong(double doubleValue)\n {\n  return BitConverter.ToInt64(BitConverter.GetBytes(doubleValue), 0);\n }\n\n static void Main()\n {\n  Console.WriteLine(ReinterpretAsDouble(0x4000000000000000));\n  Console.WriteLine(\"{0:X}\", ReinterpretAsLong(2.0));\n }\n}\n<\/pre>\n<p>Our first attempt uses the <code>Bit&shy;Converter<\/code> class to convert the 64-bit integer to an array of bytes, and then parses a double-precision floating point number from that byte array. <\/p>\n<p>Maybe you&#8217;re not happy that this creates a short-lived <code>byte[]<\/code> array that will need to be GC&#8217;d. So here&#8217;s another version that is a little sneakier. <\/p>\n<pre>\nusing System;\nusing System.Runtime.InteropServices;\n\nclass Program\n{\n [StructLayout(LayoutKind.Explicit)]\n struct LongAndDouble\n {\n  [FieldOffset(0)] public long longValue;\n  [FieldOffset(0)] public double doubleValue;\n }\n\n static double ReinterpretAsDouble(long longValue)\n {\n  LongAndDouble both;\n  both.doubleValue = 0.0;\n  both.longValue = longValue;\n  return both.doubleValue;\n }\n\n static long ReinterpretAsLong(double doubleValue)\n {\n  LongAndDouble both;\n  both.longValue = 0;\n  both.doubleValue = doubleValue;\n  return both.longValue;\n }\n ...\n}\n<\/pre>\n<p>This version creates a structure with an unusual layout: The two members occupy the same physical storage. The conversion is done by storing the 64-bit integer into that storage location, then reading the double-precision floating point value out. <\/p>\n<p>There&#8217;s a third method that involves writing the 64-bit integer to a memory stream via <code>Binary&shy;Writer<\/code> then reading it back with <code>Binary&shy;Reader<\/code>, but this is clearly inferior to the <code>Bit&shy;Converter<\/code> so I didn&#8217;t bother writing it up. <\/p>\n<p><b>Update<\/b>: Damien points out that <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2015\/06\/22\/10623021.aspx#10623129\">this functionality already exists in the BCL<\/a>: <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.bitconverter.doubletoint64bits(v=vs.110).aspx\"><code>Bit&shy;Converter.Double&shy;To&shy;Int64&shy;Bits<\/code><\/a> and <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.bitconverter.int64bitstodouble(v=vs.110).aspx\"><code>Bit&shy;Converter.Int64&shy;Bits&shy;To&shy;Double<\/code><\/a>. But there doesn&#8217;t appear to be a <code>Bit&shy;Converter.Float&shy;To&shy;Int32&shy;Bits<\/code> method, so the techniques discussed above are not completely useless. <\/p>\n<p> <b>Exercise<\/b>: Why did I have to initialize the  <code>doubleValue<\/code> before writing to <code>longValue<\/code>, and vice versa? What are the implications of the answer to the above question? (Yes, I could have written <code>LongAndDouble both = new LongAndDouble();<\/code>, which automatically zero-initializes everything, but then I wouldn&#8217;t have had an interesting exercise!) <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Punning.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-45321","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Punning.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/45321","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=45321"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/45321\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=45321"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=45321"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=45321"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}