REXX Tips & Tricks, Version 2.80


Inf-HTML [About][Toc][Index] 0.9b (c) 1995 Peter Childs


Convert Microsoft/IEEE Float binary into a string in Classic REXX



(see also Convert Microsoft/IEEE Float binary into a string in Object 
REXX) 

 
/**********************************************************************/
/* These routines are the original work of Thos Davis                 */
/* (see EMail Addresses)                                              */
/* and to the best of his knowledge do not include any copyrighted    */
/* materials.                                                         */
/*                                                                    */
/* These routines are hereby released into the Public Domain          */
/**********************************************************************/
/* Microsoft/IEEE Float binary:                                       *
  +--------------------------------------------------------------------+
  |bit |0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F|
  +====+=============================================+=+===============+
  |MKS |              mantissa                       |s|   exponent    |
  +----+---------------------------------------------+-+-------------+-|
  |IEEE|              mantissa                       |    exponent   |s|
  +--------------------------------------------------+---------------+-+
                                                                      */
/* In both cases, the mantissa is the lower (least significant)       */
/* 23 bits (plus an implied value of 1 for bit 24, the most           */
/* significant bit of the mantissa), the sign is one bit, and         */
/* the exponent is 8 bits.                                            */
/*                                                                    */
/* Because the mantissa has a 'virtual bit' whose value is always 1,  */
/* the exponent is used to determine if the value is 0.               */
/*                                                                    */
/* IEEE Double Float binary is the same format as the single Float    */
/* but the mantissa is 52 bits long (for 53 bits of significant       */
/* binary digits [is that bigits?] after including the 'virtual 1'    */
/* most significant bit) and the exponent is 11 bits long.            */
/*                                                                    */
/* !!! I M P O R T A N T !!!                                          */
/*                                                                    */
/* NUMERIC DIGITS should be set to about 16 to get the full value of  */
/* Doubles. If these procedures are made into ROUTINES, it will be    */
/* necessary to add the NUMERIC DIGITS setting to DoubleToString and  */
/* GeneralFloat.                                                      */
/*                                                                    */
/* !!! A L S O   I M P O R T A N T !!!                                */
/*                                                                    */
/* These functions do not recognize the special values                */
/*    +INF    plus infinity                                           */
/*    -INF    minus infinity                                          */
/*    +NAN    not a number                                            */
/*    -NAN    not a number                                            */
/*                                                                    */

mksToString: procedure
  TheFloat = arg(1)

                    /* mks is the format used in older versions of    */
                    /* MicroSoft BASIC and is, for some bizarre       */
                    /* reason, used as the index value in the QWK     */
                    /* BBS message packing scheme                     */

                    /* Intel uses different BYTE ordering and BIT     */
                    /* ordering so byte strings must be REVERSED to   */
                    /* make all ordering the same                     */
    bFloat = Reverse( TheFloat )

                    /* There is no c2b function                       */
    bFloat = x2b( c2x( bFloat ) )

                    /* make sure its 32 bits long                     */
    bFloat = Right( bFloat, 32, '0' )
    fMantissa = '1' || Right( bFloat, 23 )
    fExponent = Left( bFloat, 8 )
    fSign = SubStr( bFloat, 9, 1 )

                    /* I found the magicNumber values by trial and    */
                    /* error                                          */
    magicNumber = 152

return GeneralFloat( fSign, fMantissa, fExponent, magicNumber )


FloatToString: procedure
  TheFloat = arg(1)

    bFloat = Reverse( TheFloat )
    bFloat = x2b( c2x( bFloat ) )
    bFloat = Right( bFloat, 32, '0' )
    fMantissa = '1' || Right( bFloat, 23 )
    fExponent = SubStr( bFloat, 2, 8 )
    fSign = Left( bFloat, 1 )
    magicNumber = 150
return GeneralFloat( fSign, fMantissa, fExponent, magicNumber )


DoubleToString: procedure
  TheDouble = arg(1)

    bDouble = Reverse( TheDouble )
    bDouble = x2b( c2x( bDouble ) )
    bDouble = Right( bDouble, 64, '0' )
    dMantissa = '1' || Right( bDouble, 52 )
    dExponent = SubStr( bDouble, 2, 11 )
    dSign = Left( bDouble, 1 )
    magicNumber = 1075
return GeneralFloat( dSign, dMantissa, dExponent, magicNumber )


GeneralFloat: procedure
  theSign = arg(1)
  theMantissa = arg(2)
  theExponent = arg(3)
  magicNumber = arg(4)

    if theExponent = 0 then
        ascFloat = 0
    else
      do
        decMantissa = x2d( b2x( theMantissa ) )
        decExponent = x2d( b2x( theExponent ) )
        ascFloat = decMantissa * ( 2 ** ( decExponent - magicNumber ))
      end

    if theSign then
        ascFloat = '-'ascFloat

return ascFloat



AN ADDENDUM 
While converting from binary fractions to decimal fractions has some 
inherent inaccuracies, the REXX procedures I gave have some additional 
ones built in.  REXX does not use binary arithmetic (at least it is not 
supposed to).  Instead it uses decimal methods modeled on human arithmetic 
systems.  This gives better results for decimal numbers, but tends to make 
arithmetic with binary fractions somewhat less accurate. 
Because of this, and because I use arithmetic on the numbers when 
converting, _sometimes_ 'conversion artifacts' will be introduced which 
result in a representation slightly greater or less than the value which 
is returned by standard C library functions (e.g.  printf() ). For example 
0.5 decimal (1/2), which is 0.1 binary, should translate perfectly from 
one system to the other, will be translated from the double to 
0.5000000000000002 using DoubleToString.  Likewise 0.0625 decimal (1/16), 
which is 0.0001 binary, is translated as 0.06250000000000001. 
Additionally, the results are dependent on the value of NUMERIC DIGITS. 
For example:  1.0 is translated by FloatToString() as 0.99999999999 when 
NUMERIC DIGITS is set to 11 (decimal), and 0.5 (decimal) is translated by 
DoubleToString as 0.49999999999999999999 when NUMERIC DIGITS is 20. 
It is important to note that the actual value stored in the file is not 
changed. 
If it is important to see very precise translations, these procedures may 
not be for you.  However, with the information on the format of the 
numbers, you may be able to devise your own conversion procedures. 
Additionally, I did not include the IEEE +INFINITY, -INFINITY, 
+NOT-A-NUMBER, and -NOT-A-NUMBER, because I do not have documentation on 
these values.  However, based on actual conversions by Borland's C++ for 
OS/2 (version 1.5), I am led to believe that an exponent whose bits are 
all set to 1 indicates a SPECIAL VALUE.  If the exponent is all ones, and 
the mantissa (with the virtual bit) has only its most significant bit set 
to 1, then that is INFINITY (+/- depending on the sign), and if the two 
most significant bits (including the virtual bit) are both set to 1 and no 
other bits in the mantissa are set to 1, then that is NOT-A-NUMBER.  If 
the other bits are set to 1, I don't know what that means. 
I use a test for the special exponent in my own routines (I use 
ObjectREXX) and then call SpecialFloat if it matches.  If you use this 
type of procedure, then it may be necessary for your program to test for 
these values before performing additional math on them!  I do not know if 
the MicroSoft Format used by early versions of BASIC has any special 
values.   

 
::ROUTINE FloatToString PUBLIC
    ...

    if fExponent = '11111111' then
      return SpecialFloat( fSign, fMantissa, 'S' )
    else
      return GeneralFloat( ... )


::ROUTINE SpecialFloat
  use arg theSign, theMantissa, theType

    SELECT
      WHEN theType = 'S' then lenMantissa = 24
      WHEN theType = 'D' then lenMantissa = 53
    END

    SELECT
      WHEN theMantissa = '1'˜Left( lenMantissa, '0' ) THEN
        ieeeSpecial = 'INFINITY'
      WHEN theMantissa = '11'˜Left( lenMantissa, '0' ) THEN
        ieeeSpecial = 'NOT-A-NUMBER'
      OTHERWISE
        ieeeSpecial = 'UNKNOWN-MEANING'
    END /* SELECT */

    if theSign then
      ieeeSpecial = '-'ieeeSpecial
    else
      ieeeSpecial = '+'ieeeSpecial

    return 'IEEE:' ieeeSpecial

  

Inf-HTML End Run - Successful