* harbour/harbour.spec
* harbour/mpkg_tgz.sh
+ added hbformat
* harbour/include/hbdefs.h
* harbour/include/hbapi.h
* harbour/source/common/hbarch.c
* redefined macros used to store/retrieve integer and double values
to/from byte arrays in little and big endian order.
Now GCC uses inline functions which are hardly optimized by compiler
giving on x86 machines the same code as direct casting (with the
exception to march=i686 where putting double value forces strict
alignment to avoid hidden CPU exception) but they respect strict
aliasing rules. It also means that now GCC builds always respect
strict alignment even if HB_STRICT_ALIGNMENT macro is not set.
326 lines
9.5 KiB
C
326 lines
9.5 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* xHarbour Project source code:
|
|
* Architecture dependent conversions
|
|
*
|
|
* Copyright 2005 Przemyslaw Czerpak <druzus@acn.waw.pl>
|
|
* www - http://www.xharbour.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
#include "hbapi.h"
|
|
#include "hbmath.h"
|
|
|
|
/*
|
|
* functions hb_put_ieee754() and hb_get_ieee754() stores / retrieve
|
|
* IEEE754 double value making conversion from/to native C double type.
|
|
* They should be used on platforms which does not use IEEE754 double
|
|
* and user needs binary compatibility, f.e. he wants to share CDXs or
|
|
* or DBFs with "B" fields with other station or use common .hrb files
|
|
* functions hb_put_ord_ieee754() and hb_get_ord_ieee754() converts
|
|
* to/from special modified IEEE754 double form used by some index formats
|
|
* like CDX or NSX to create index keys. In this form double numbers can
|
|
* be sorted as 8-bytes character values (f.e. with memcmp())
|
|
*/
|
|
|
|
#define HB_MANTISSA_BITS 52
|
|
#define HB_MANTISSA_MASK ( ( ( UINT64 ) 1 << HB_MANTISSA_BITS ) - 1 )
|
|
#define HB_EXPONENT_BITS 11
|
|
#define HB_EXPONENT_MASK ( ( 1 << HB_EXPONENT_BITS ) - 1 )
|
|
#define HB_EXPONENT_ADD 0x3ff
|
|
|
|
void hb_put_ieee754( BYTE * ptr, double d )
|
|
{
|
|
int iExp, iSig;
|
|
double df;
|
|
#if defined( HB_LONG_LONG_OFF )
|
|
UINT32 l1, l2;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_put_ieee754(%p, %f)", ptr, d));
|
|
|
|
iSig = d < 0 ? 1 : 0;
|
|
if( d == 0.0 )
|
|
{
|
|
l1 = l2 = 0;
|
|
}
|
|
else
|
|
{
|
|
df = frexp( iSig ? -d : d, &iExp );
|
|
l1 = ( UINT32 ) ldexp( df, HB_MANTISSA_BITS + 1 );
|
|
l2 = ( UINT32 ) ldexp( df, HB_MANTISSA_BITS + 1 - 32 ) &
|
|
( ( ( UINT32 ) 1 << ( HB_MANTISSA_BITS - 32 ) ) - 1 );
|
|
l2 |= ( UINT32 ) ( ( iExp + HB_EXPONENT_ADD - 1 ) & HB_EXPONENT_MASK ) <<
|
|
( HB_MANTISSA_BITS - 32 );
|
|
}
|
|
l2 |= ( UINT32 ) iSig << ( HB_MANTISSA_BITS + HB_EXPONENT_BITS - 32 );
|
|
HB_PUT_LE_UINT32( ptr, l1 );
|
|
HB_PUT_LE_UINT32( ptr + 4, l2 );
|
|
#else
|
|
UINT64 ll;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_put_ieee754(%p, %f)", ptr, d));
|
|
|
|
iSig = d < 0 ? 1 : 0;
|
|
if( d == 0.0 )
|
|
{
|
|
ll = 0;
|
|
}
|
|
else
|
|
{
|
|
df = frexp( iSig ? -d : d, &iExp );
|
|
ll = ( UINT64 ) ldexp( df, HB_MANTISSA_BITS + 1 ) & HB_MANTISSA_MASK;
|
|
ll |= ( UINT64 ) ( ( iExp + HB_EXPONENT_ADD - 1 ) & HB_EXPONENT_MASK ) <<
|
|
HB_MANTISSA_BITS;
|
|
}
|
|
ll |= ( UINT64 ) iSig << ( HB_MANTISSA_BITS + HB_EXPONENT_BITS );
|
|
HB_PUT_LE_UINT64( ptr, ll );
|
|
#endif
|
|
}
|
|
|
|
double hb_get_ieee754( const BYTE * ptr )
|
|
{
|
|
int iExp, iSig;
|
|
#if defined( HB_LONG_LONG_OFF )
|
|
UINT32 l1, l2;
|
|
double d;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_get_ieee754(%p)", ptr));
|
|
|
|
l1 = HB_GET_LE_UINT32( ptr );
|
|
l2 = HB_GET_LE_UINT32( ptr + 4 );
|
|
iSig = ( int ) ( l2 >> ( HB_MANTISSA_BITS + HB_EXPONENT_BITS - 32 ) ) & 1;
|
|
iExp = ( int ) ( ( l2 >> ( HB_MANTISSA_BITS - 32 ) ) & HB_EXPONENT_MASK );
|
|
l2 &= ( ( UINT32 ) 1 << ( HB_MANTISSA_BITS - 32 ) ) - 1;
|
|
|
|
if( ( l1 | l2 | iExp ) != 0 )
|
|
l2 |= ( UINT32 ) 1 << ( HB_MANTISSA_BITS - 32 );
|
|
|
|
d = ldexp( ( double ) l2, 32 ) + ( double ) l1;
|
|
return ldexp( iSig ? -d : d, iExp - HB_MANTISSA_BITS - HB_EXPONENT_ADD );
|
|
#else
|
|
UINT64 ll;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_get_ieee754(%p)", ptr));
|
|
|
|
ll = HB_GET_LE_UINT64( ptr );
|
|
iSig = ( int ) ( ll >> ( HB_MANTISSA_BITS + HB_EXPONENT_BITS ) ) & 1;
|
|
iExp = ( int ) ( ( ll >> HB_MANTISSA_BITS ) & HB_EXPONENT_MASK );
|
|
ll &= HB_MANTISSA_MASK;
|
|
if( ( ll | iExp ) != 0 )
|
|
ll |= ( UINT64 ) 1 << HB_MANTISSA_BITS;
|
|
/* the casting form UINT64 to INT64 is necessary for some
|
|
compilers which does not support UINT64 -> double conversion
|
|
It will not change results because there is only up to 53bits
|
|
set in mantissa */
|
|
return ldexp( iSig ? -( double ) ( INT64 ) ll : ( double ) ( INT64 ) ll,
|
|
iExp - HB_MANTISSA_BITS - HB_EXPONENT_ADD );
|
|
#endif
|
|
}
|
|
|
|
void hb_put_ord_ieee754( BYTE * ptr, double d )
|
|
{
|
|
int iExp, iSig;
|
|
double df;
|
|
UINT32 l1, l2;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_put_ord_ieee754(%p, %f)", ptr, d));
|
|
|
|
iSig = d < 0 ? 1 : 0;
|
|
if( d == 0.0 )
|
|
{
|
|
l1 = l2 = 0;
|
|
}
|
|
else
|
|
{
|
|
df = frexp( iSig ? -d : d, &iExp );
|
|
l1 = ( UINT32 ) ldexp( df, HB_MANTISSA_BITS + 1 );
|
|
l2 = ( UINT32 ) ldexp( df, HB_MANTISSA_BITS + 1 - 32 ) &
|
|
( ( ( UINT32 ) 1 << ( HB_MANTISSA_BITS - 32 ) ) - 1 );
|
|
l2 |= ( UINT32 ) ( ( iExp + HB_EXPONENT_ADD - 1 ) & HB_EXPONENT_MASK ) <<
|
|
( HB_MANTISSA_BITS - 32 );
|
|
}
|
|
if( iSig )
|
|
{
|
|
l2 ^= 0x7FFFFFFFL;
|
|
l1 ^= 0xFFFFFFFFL;
|
|
}
|
|
else
|
|
{
|
|
l2 ^= 0x80000000L;
|
|
}
|
|
HB_PUT_BE_UINT32( ptr, l2 );
|
|
HB_PUT_BE_UINT32( ptr + 4, l1 );
|
|
}
|
|
|
|
double hb_get_ord_ieee754( const BYTE * ptr )
|
|
{
|
|
int iExp, iSig;
|
|
UINT32 l1, l2;
|
|
double d;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_get_ord_ieee754(%p)", ptr));
|
|
|
|
l1 = HB_GET_BE_UINT32( ptr + 4 );
|
|
l2 = HB_GET_BE_UINT32( ptr );
|
|
iSig = ( l2 & 0x80000000L ) ? 0 : 1;
|
|
if( iSig )
|
|
{
|
|
l2 ^= 0x7FFFFFFFL;
|
|
l1 ^= 0xFFFFFFFFL;
|
|
}
|
|
iExp = ( ( l2 >> ( HB_MANTISSA_BITS - 32 ) ) & HB_EXPONENT_MASK );
|
|
l2 &= ( ( UINT32 ) 1 << ( HB_MANTISSA_BITS - 32 ) ) - 1;
|
|
|
|
if( ( l1 | l2 | iExp ) != 0 )
|
|
l2 |= ( UINT32 ) 1 << ( HB_MANTISSA_BITS - 32 );
|
|
|
|
d = ldexp( ( double ) l2, 32 ) + ( double ) l1;
|
|
return ldexp( iSig ? -d : d, iExp - HB_MANTISSA_BITS - HB_EXPONENT_ADD );
|
|
}
|
|
|
|
/*
|
|
* I added function hb_get_rev_double() and hb_get_std_double() because
|
|
* some compilers does not like constraction used by in HB_GET_LE_DOUBLE
|
|
* macro => d = { ... }
|
|
*/
|
|
double hb_get_rev_double( const BYTE * ptr )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_get_rev_double(%p)", ptr));
|
|
|
|
{
|
|
#if defined( __GNUC__ )
|
|
return _hb_get_rev_double( ptr );
|
|
#else
|
|
union {
|
|
double dbl;
|
|
BYTE buffer[ 8 ];
|
|
} u;
|
|
|
|
u.buffer[ 0 ] = ptr[ 7 ];
|
|
u.buffer[ 1 ] = ptr[ 6 ];
|
|
u.buffer[ 2 ] = ptr[ 5 ];
|
|
u.buffer[ 3 ] = ptr[ 4 ];
|
|
u.buffer[ 4 ] = ptr[ 3 ];
|
|
u.buffer[ 5 ] = ptr[ 2 ];
|
|
u.buffer[ 6 ] = ptr[ 1 ];
|
|
u.buffer[ 7 ] = ptr[ 0 ];
|
|
|
|
return u.dbl;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
double hb_get_std_double( const BYTE * ptr )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_get_std_double(%p)", ptr));
|
|
|
|
{
|
|
#if defined( __GNUC__ )
|
|
return _hb_get_std_double( ptr );
|
|
#else
|
|
union {
|
|
double dbl;
|
|
BYTE buffer[ 8 ];
|
|
} u;
|
|
|
|
u.buffer[ 0 ] = ptr[ 0 ];
|
|
u.buffer[ 1 ] = ptr[ 1 ];
|
|
u.buffer[ 2 ] = ptr[ 2 ];
|
|
u.buffer[ 3 ] = ptr[ 3 ];
|
|
u.buffer[ 4 ] = ptr[ 4 ];
|
|
u.buffer[ 5 ] = ptr[ 5 ];
|
|
u.buffer[ 6 ] = ptr[ 6 ];
|
|
u.buffer[ 7 ] = ptr[ 7 ];
|
|
|
|
return u.dbl;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if defined( HB_LONG_LONG_OFF )
|
|
|
|
/*
|
|
* The function below are only for platforms which do not support
|
|
* 64 but integer values. So the convert them to/from 'double'
|
|
* values. They are necessary for extracting such number from PCODE,
|
|
* databases or serialization streams in RPC
|
|
*/
|
|
double hb_get_le_uint64( const BYTE * ptr )
|
|
{
|
|
UINT32 l1, l2;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_get_le_uint64(%p)", ptr));
|
|
|
|
l1 = HB_GET_LE_UINT32( ptr );
|
|
l2 = HB_GET_LE_UINT32( ptr + 4 );
|
|
return ldexp( ( double ) l2, 32 ) + ( double ) l1;
|
|
}
|
|
|
|
double hb_get_le_int64( const BYTE * ptr )
|
|
{
|
|
UINT32 l1;
|
|
INT32 l2;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_get_le_int64(%p)", ptr));
|
|
|
|
l1 = HB_GET_LE_UINT32( ptr );
|
|
l2 = HB_GET_LE_INT32( ptr + 4 );
|
|
return ldexp( ( double ) l2, 32 ) + ( double ) l1;
|
|
}
|
|
|
|
void hb_put_le_uint64( BYTE * ptr, double d )
|
|
{
|
|
UINT32 l1, l2;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_put_le_uint64(%p)", ptr));
|
|
|
|
l1 = ( UINT32 ) ( d );
|
|
l2 = ( UINT32 ) ( d / 4294967296.0 );
|
|
HB_PUT_LE_UINT32( ptr, l1 );
|
|
HB_PUT_LE_UINT32( ptr + 4, l2 );
|
|
}
|
|
|
|
#endif
|