Converting float NaN values from binary form and vice-versa results a mismatch

Dmitry Razumikhin

I make a conversion "bytes[4] -> float number -> bytes[4]" without any arithmetics. In bytes I have a single precision number in IEEE-754 format (4 bytes per number, little endian order as in a machine). I encounter a issue, when bytes represents a NaN value converted not verbatim. For example:

{ 0x1B, 0xC4, 0xAB, 0x7F } -> NaN -> { 0x1B, 0xC4, 0xEB, 0x7F }

Code for reproduction:

using System;
using System.Linq;

namespace StrangeFloat
{
    class Program
    {
        private static void PrintBytes(byte[] array)
        {
            foreach (byte b in array)
            {
                Console.Write("{0:X2}", b);
            }
            Console.WriteLine();
        }

        static void Main(string[] args)
        {
            byte[] strangeFloat = { 0x1B, 0xC4, 0xAB, 0x7F };
            float[] array = new float[1];
            Buffer.BlockCopy(strangeFloat, 0, array, 0, 4);
            byte[] bitConverterResult = BitConverter.GetBytes(array[0]);

            PrintBytes(strangeFloat);
            PrintBytes(bitConverterResult);
            bool isEqual = strangeFloat.SequenceEqual(bitConverterResult);
            Console.WriteLine("IsEqual: {0}", isEqual);
        }
    }
}

Result ( https://ideone.com/p5fsrE ):

1BC4AB7F
1BC4EB7F
IsEqual: False

This behaviour depends from platform and configuration: this code convert a number without errors on x64 in all configurations or in x86/Debug. On x86/Release an error exists.

Also, if I change

byte[] bitConverterResult = BitConverter.GetBytes(array[0]);

to

float f = array[0];
byte[] bitConverterResult = BitConverter.GetBytes(f);

then it erroneus also on x86/Debug.

I do research the problem and found that compiler generate x86 code that use a FPU registers (!) to a hold a float value (FLD/FST instructions). But FPU set a high bit of mantissa to 1 instead of 0, so it modify value although logic was is just pass a value without change. On x64 platform a xmm0 register used (SSE) and it works fine.

[Question]

What is this: it is a somewhere documented undefined behavior for a NaN values or a JIT/optimization bug?

Why compiler use a FPU and SSE when no arithmetic operations was made?

Update 1

Debug configuration - pass value via stack without side effects - correct result:

    byte[] bitConverterResult = BitConverter.GetBytes(array[0]);
02232E45  mov         eax,dword ptr [ebp-44h]  
02232E48  cmp         dword ptr [eax+4],0  
02232E4C  ja          02232E53  
02232E4E  call        71EAC65A  
02232E53  push        dword ptr [eax+8]   // eax+8 points to "1b c4 ab 7f" CORRECT!
02232E56  call        7136D8E4  
02232E5B  mov         dword ptr [ebp-5Ch],eax // eax points to managed
// array data "fc 35 d7 70 04 00 00 00 __1b c4 ab 7f__" and this is correct
02232E5E  mov         eax,dword ptr [ebp-5Ch]  
02232E61  mov         dword ptr [ebp-48h],eax 

Release configuration - optimizer or a JIT does a strange pass via FPU registers and breaks a data - incorrect

    byte[] bitConverterResult = BitConverter.GetBytes(array[0]);
00B12DE8  cmp         dword ptr [edi+4],0  
00B12DEC  jbe         00B12E3B  
00B12DEE  fld         dword ptr [edi+8]     // edi+8 points to "1b c4 ab 7f"
00B12DF1  fstp        dword ptr [ebp-10h]   // ebp-10h points to "1b c4 eb 7f" (FAIL)
00B12DF4  mov         ecx,dword ptr [ebp-10h]  
00B12DF7  call        70C75810  
00B12DFC  mov         edi,eax  
00B12DFE  mov         ecx,esi  
00B12E00  call        dword ptr ds:[4A70860h] 
Dmitry Razumikhin

I just translate @HansPassant comment as an answer.

"The x86 jitter uses the FPU to handle floating point values. This is not a bug. Your assumption that those byte values are a proper argument to a method that takes a float argument is just wrong."

In other words, this is just a GIGO case (Garbage In, Garbage Out).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Converting Secret Key into a String and Vice Versa

"Converting" Numpy arrays to Matlab and vice versa

"Converting" Numpy arrays to Matlab and vice versa

Convert binary to ASCII and vice versa

Converting Strings to encryption keys and vice versa java

How to convert a float into a byte array and vice versa?

Overhead of converting from []byte to string and vice-versa

Converting XDocument to XmlDocument and vice versa

Converting QString to Ascii value & Vice Versa in Qt

Converting a preorder traversal array to an level order traversal array (or vice versa) given that the binary tree was filled in Level Order

Converting an Armadillo Matrix to an Eigen MatriXd and vice versa

Converting Input text from lowercase to uppercase and vice versa in Javascript

Converting String to Byte Array and vice versa

How to convert 16bit hexadecimal and binary representations to decimal float (and vice versa) in python?

Converting from smaller data type to bigger and vice versa

Converting pandas dataframe to dict and vice versa

Converting Object Data type to float data type in pandas results NaN values

Converting Double to Float and vice versa manually

Converting a population on a grid to coordinates, and vice versa

Converting base 6 to decimal and vice versa in Python?

Access form methods and variables from a class and vice versa in C#

Parsing a binary file written in MATLAB from Python and vice versa

Accessing class from form and vice-versa

R - Converting formulae to character strings and vice versa

Converting string to integer and vice versa in Python

Converting from Instant to XMLGregorianCalendar and vice-versa without losing precision

Python - making and int from 8 boolean byte values and vice versa

Java - Converting String from Scanner to int and vice versa

Converting char to binary strings and vice-versa

TOP Ranking

HotTag

Archive