?
Solved

How can I implement a function like the dmsbintoieee() of old?

Posted on 2003-02-19
4
Medium Priority
?
338 Views
Last Modified: 2008-03-17
I need to convert Microsoft binary format doubles saved in a file, like those used in VB3, to doubles I can use in C++.

The old 16 bit function was dmsbintoieee( double *, double * )

I think it was in math.lib, but I can't find an equivilent now and I am desparate.

I will accept either the name of the function supplied in VC++ 6.0 that does this, or instructions on how to convert the little devils.

I am offering big points because I need a quick answer.
0
Comment
Question by:duncanlatimer
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
4 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 1600 total points
ID: 7982504
Check out http://groups.google.com/groups?hl=de&lr=&ie=UTF-8&oe=UTF-8&selm=uNjnwWN68GA.307%40upnetnews03&rnum=2 - it seems to have the answer:

typedef union _mbf_dbl_t
{
   double d;
   unsigned short i[4];
   unsigned long l[2];
} Mbfd_t;
int DMsbinToIeee( double *source, double *dest )
// ---[comments reformatted for line breaks. - felixk]---
// Description:
//    This function was written by Felix A. Kasza [MVP on MSLANG
//    Compuserve forum] as a sample of what is required to convert
//    a Microsoft binary format double precision number to an ieee
//    format double.
// Parameters:
//    source - pointer to MBF format double to convert
//    dest - pointer to buffer for ieee result
// Return:
//    0 - conversion was successful
//    1 - overflow
// Shared Data:
//    none
// Use of Other Routines:
//    none
// Assumptions/Cautions:
//    The routine assumes that the MBF double is normalized.
//
//    Some precision may be lost because the ieee format uses fewer
//    bits for the mantissa.
{
   int      shifts;
   Mbfd_t   ie; // will hold converted value
   Mbfd_t   mb; // temporary storage for MBF value
   // Copy the number to be converted to a union for easier handling.
   mb.d = *source;
   // I special-case all-zero because the exponent should not
   // be biased. Rather, 0 is represented by a pattern of all
   // binary zeroes.
   if ( mb.l[0] == 0L && mb.l[1] == 0L ) {
      *dest = 0.0;
       return 0;
      }
   // get exponent value
   ie.i[3] = (unsigned short) mb.i[3] >> 8;
   // ie.i[3] now has an exponent still biased by 0x80
   // adjust by -1 to compensate for 0.111... vs. 1.111...
   ie.i[3] += 894; // convert to 1023 bias (+1023 - 128 - 1)
   // left-adjust, leaving one bit for the sign
   ie.i[3] <<= 4; // 00000xxxxxxxxxxxx ==> 0xxxxxxxxxxx0000
   // next line ORs the sign bit into the word containing the exp.
   ie.i[3] |= ( mb.i[3] & 0x0080 )? 0x8000: 0x0000;
   // next line gets four bits of mantissa which will fit into the
   // exponent word
   ie.i[3] |= (unsigned short) ( mb.i[3] >> 3 ) & 0x000f;
   // now we have 6-3/8 bytes mantissa left to shoehorn into 6 bytes.
   // we do that by right-shifting the entire mbf by three bits and
   // masking off what we don't need. this would be easier if C
   // had a roll-through-carry operator.
   for ( shifts = 0; shifts < 3; shifts ++ )
   {
      mb.l[0] >>= 1; // shift low doubleword
      // the next line examines the lowest bit of the high dword
      // which must become the highest bit of the low dword. if
      // it is set, the low dword gets ORed with a 1 in the highest
      // bit position. I wish we'd be doing this in the assembly
      // section ...
      mb.l[0] |= ( mb.l[1] & 0x00000001L )? 0x80000000L: 0L;
      // shift the high dword now. the lowest bit gets lost which is
      // why we checked it above.
      mb.l[1] >>= 1;
   }
   // now, ignore the highest 16 bits (which in the IEEE number we
   // already filled) and transfer the remaining 48 bits
   ie.i[2] = mb.i[2];
   ie.i[1] = mb.i[1];
   ie.i[0] = mb.i[0];
   // THAT'S IT!
   *dest = ie.d;
   return 0;
}     // End DMsbinToIeee()
0
 
LVL 12

Expert Comment

by:Salte
ID: 7982758
This is likely some simple bit manipulation. However, it require that you know the format of the dmsbin format.

Do you have any documentation of it anywhere or can you find such info?

All floating point formats are based on the following format:

a double or floating point value is divided into three sections:

   MSB                            LSB
  |s|exponent|mantissa..............|

The most significant bit is the sign bit, if 0 the number is positive and if 1 the number is negative. This should be the same in both formats.

exponent is the next field counting form the most significant bits. This field is used to hold the exponent of the number. This value is a biased integer and different floating point formats differ in how many bits they use for this field and in the value of the bias. There are also typically two special values for exponent (all bits 0 and all bits 1) that has special meaning and deserve special attention. If the format does not treat the form with all bits 1 special then that in itself is special. (they normally do).

The remainder of the number is the mantissa and again the different formats differ in how many bits they include in the mantissa but they also differ in wether they include the most significant bit or not.

The point is that mantissa is interpreted differently depending on if the exponent is special (all bits 0 or all bits 1) or regular (mix of 0 and 1).

For regular mantissa, the mantissa is often adjusted to be a number such that 0.5 <= Mantissa < 1.0

Since the mantissa is always >= 0.5 and always less than 1 then in binary form it is always written as 0.1xxxxx since that first digit after the binary point (like decimal point but we're talking binary representation here) is always 1 there's no reason why you should store it. However, some formats do store the value while other formats do not. Those who do not has of course one extra bit of precision compared to those that always include that 1 bit.

The mantissa itself is stored as an integer M which is scaled so that M * 2^scale for a fixed scale factor such that 0 <= M < 0.5 you then add 0.5 and get the value in the aforementioned range 0.5 <= mantissa < 1.0 to compute the value that the floating point number represent. The scale is of course negative since the integer is usually a very high value.

The exponent is stored as a biased integer. This means that the value is in the range 0 <= exponent < pow(2,number of bits for exponent)

However, we also want to store negative values and so about half of that range is used to store negative values. The solution is to bias the value so that an exponent of 0 isn't stored as 0 (all bits 0) but  rather as a value BIAS.  An exponent of 1 is stored as BIAS + 1 etc. An exponent of -5 is then stored as BIAS - 5. Since BIAS is a very high value you can store a wide range of positive and negative exponents this way.

So, now you know how floating point values are stored, how to decode them? I can give you the parameters for the IEEE decoding used on the PC - the one that C++'s double on the PC is encoded in.

1 sign bit - 0 means positive 1 means negative.
exponent - 9 bits and bias is 0x0ff. or 255. A value of 0x001 (minimum regular value) in this field indicate an exponent of -254 while a value of 0x1fe means an exponent of -1. 0x1ff means an exponent of 0, 0x200 means an exponent of 1 and 0x3fe (maximum regular value) means an exponent of +255.

The value 0 is special and if mantissa is also 0 then this encodes the double value 0. I.e. 0.0 == all bits 0. However the value 1000000...00 would also be -0.0 is also 0.

If mantissa is not 0 then the value hold a unormalized value which is a way to represent very small values (very close to 0) Essentially the value is computed using the exponent as a regular exponent but the mantissa do not get the usual 0.5 added to it so the mantissa is very small.

The exponent value of all bits 1 (0x3ff) is also special and is used to encode INFINITY and not-a-number.

If mantissa is 0 the value is infinity if I remember correctly, the sign bit counts and we differ between -INF and +INF.

If mantissa is not 0 the value is 'not-a-number'. I think the mantissa bits is ignored (as long as they are not all 0) and when setting is set to a fixed pattern.

The remaining 54 bits holds the mantissa and when the exponent is regular you get the extra 0.5 so the most significant bit of the mantissa is not stored.

Once you figure out the format of the old visual basic it is then possible to convert the values. Probably extend or shrink the exponent, add zero bits at end of mantissa or shrink the mantissa. Maybe remove the top bit of the mantissa which isn't used in the IEEE format (it is always 1 and is implied). etc etc

Alf
0
 
LVL 86

Expert Comment

by:jkr
ID: 7982873
>>However, it require that you know the format of the dmsbin format

Err, there's already a detailed description of this format in the above link :o)

But, as we are already repeating, I might it post here as well also...

The MS binary format (MBF) consists of an 8bit binary exponent in the
first byte (unsigned, exponent biased by 80h), followed by a sign bit,
followed by a 55bit or 23bit mantissa (depending on whether we talk
double or single precision). The first digit of the full 56bit
mantissa would always be a binary 1, so they used this bit position
for the sign of the number. The mantissa itself is unsigned (IOW,
stored as sign and absolute value, not in 2's complement).
Here is what 1.5 looks like in 8byte MBF (hex):
    81 40 00 00 00 00 00 00
81 says the exponent is 1, so we have to multiply the mantissa by 2^1
== 2. 40h is 01000000 binary; the first bit is the sign (0 ==
positive). Let's remember that and put the implied "1" back in:
    11000000 (followed by 6 bytes of 00000000)
That's the mantissa. The binary point is to the left, so what we have
here is 1 half plus 1 fourth plus 0 eighths plus 0 sixteenths ... The
mantissa is therefore 3 fourths, or 0.75 in decimal. Multiplied by the
2^1, that gives 1.5.
Now for the IEEE side of things. We'll only look at 8byte reals (the
familiar "double" type). IEEE format sacrifices precision for extended
range; it uses an 11bit exponent, biased by 1023, and accordingly has
only 52bits of mantissa (53 if we count the implied "1" bit). Also, it
has the mantissa's sign in front, as the most significant bit of the
most significant byte. (Reminds me -- all values I show here start
with the highest byte and end with the lowest byte, contrary to the
memory representation of things.) Another, minor, difference is that
the binary point is not before the implied "1" bit but _after_ it.
That means we'll have to adjust the exponent bias by 1.
The sequence of steps needed to convert an MBF number to a double is
therefore:
 - get the sign bit, stick it into the double
 - get and unbias the exponent, bias by 1023, right-adjust into 11bit
   field in the double
 - get and truncate the mantissa (excluding the MBF sign), left-align
   into the mantissa field in the double
0
 

Author Comment

by:duncanlatimer
ID: 7986157
jkr, you are great, I was in a real pickle and you came through fast!
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
Suggested Courses

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question