Integral and fractional parts of a number

138 views
Skip to first unread message

Luigi Ferraris

unread,
Nov 21, 2022, 10:30:31 AM11/21/22
to Harbour Users
Hi friends,
I need to know decimal part of a number (real, floating) if it's near/closest to zero.
I start to write a function but I'm in already in a trouble to get fractional part.

LOCAL number := 0.0001
LOCAL decPart := number - INT( number )
? hb_NtoC( decPart ) ==> 0.0001 seems ok


LOCAL number := 1.0001
LOCAL decPart := number - INT( number )
? hb_NtoC( decPart ) ==> 0.00009999999999998899
probably due to Harbour internal number handling.

It seems to me that (probably) I can't do math operation using Xbase,
but I need to call an internal Harbour C function to get fractional and integral part
on the "original" value (iow bypass internal Harbour math handling/rounding).

So, the question is: with Harbour, how can retrieve integer and decimal part of a number?

Best regards
Luigi

jgt

unread,
Nov 21, 2022, 2:45:28 PM11/21/22
to Harbour Users

?hb_NtoC(decPart,6,5)

Bernard Mouille

unread,
Nov 21, 2022, 3:24:21 PM11/21/22
to Harbour Users
Hello Luigi,
The same result with my computer.
Is is ok with hb_ntos( decPart )
Regards,
Bernard.

gfil...@gmail.com

unread,
Nov 22, 2022, 8:23:54 AM11/22/22
to Harbour Users
Hi Luigi,

This problem was discussed on the Russian Harbour forum too.

Please take a look for the results of the sample below:

proc main

LOCAL number := 1.0001
LOCAL decPart := number - INT( number )
Local cld := ld_set( decPart )

? hb_NtoC( decPart )  // 22

? ld_str(cld, 8)  // 0.000100
? ld_str(cld,, 18)
? ld_str(cld, 24, Len( hb_NtoC( decPart ) ))
? ld_str(cld, 40, 34)
wait
retu

#pragma BEGINDUMP

#include "hbapi.h"

#define ld_len sizeof( long double )

typedef union
{
   long double value;
   char string[ ld_len ];
} xld16;

HB_FUNC( LD_SET )
{
   xld16 ld;

   ld.value = hb_parnd( 1 );

   hb_retclen( ( char * ) &ld, ld_len );

}

static xld16 ld_get( int iPar )
{
   HB_SIZE ulLen = hb_parclen( iPar );
   const char *szLD = hb_parc( iPar );
   xld16 ld;

   if( ulLen == ld_len )
      memcpy( &ld.string, szLD, ld_len );
   else
      ld.value = 0.0;
   return ld;
}

HB_FUNC( LD_GET )
{
   xld16 ld = ld_get( 1 );

   hb_retnd( ld.value );
}

HB_FUNC( LD_ADD )
{
   xld16 ld1 = ld_get( 1 );
   xld16 ld2 = ld_get( 2 );
   xld16 ld;

   ld.value = ld1.value + ld2.value;

   hb_retclen( ( char * ) &ld, ld_len );
}

HB_FUNC( LD_SUB )
{
   xld16 ld1 = ld_get( 1 );
   xld16 ld2 = ld_get( 2 );
   xld16 ld;

   ld.value = ld1.value - ld2.value;

   hb_retclen( ( char * ) &ld, ld_len );
}

HB_FUNC( LD_MUL )
{
   xld16 ld1 = ld_get( 1 );
   xld16 ld2 = ld_get( 2 );
   xld16 ld;

   ld.value = ld1.value * ld2.value;

   hb_retclen( ( char * ) &ld, ld_len );
}

HB_FUNC( LD_DIV )
{
   xld16 ld1 = ld_get( 1 );
   xld16 ld2 = ld_get( 2 );
   xld16 ld;

   ld.value = ld1.value / ld2.value;

   hb_retclen( ( char * ) &ld, ld_len );
}

HB_FUNC( LD_STR )
{
   int iLen = hb_parni( 2 ), iDec = hb_parni( 3 ), iLen1;
   xld16 ld = ld_get( 1 );
   char szStr[50];
   char sFormat[10];
   int iFmtLen = 1;

   sFormat[0] = '%';
   if( iDec > 0 )
   {
      char sDec[10];
      sFormat[1] = '.';
      itoa( iDec, sDec, 10 );
      memcpy( sFormat + 2, sDec, strlen( sDec ) );
      iFmtLen += 1 + strlen( sDec );
   }
   sFormat[ iFmtLen ] = 'L';
   sFormat[ iFmtLen + 1 ] = 'f';
   sFormat[ iFmtLen + 2 ] = 0;

#if defined(__MINGW32__) || defined(__MINGW64__)
   __mingw_snprintf(szStr, 50, sFormat, ld.value );
#else
   snprintf(szStr, 50, sFormat, ld.value );
#endif

   iLen1 = strlen( szStr );
   if( iLen > 0 && iLen > iLen1 )
   {
      if( iLen1 < iLen && iLen < 39 )
      {
         int i;
         for( i = iLen1 - 1; i >= 0; i -- )
            szStr[ i + ( iLen - iLen1 )] = szStr[ i ];
         memset( szStr, ' ', iLen - iLen1 );
         iLen1 = iLen;
      }
   }

   hb_retclen( szStr, iLen1 );
}

#pragma ENDDUMP

May be it is a solution for you...

Regards,
Grigory

понедельник, 21 ноября 2022 г. в 16:30:31 UTC+1, Luigi Ferraris:

Luigi Ferraris

unread,
Nov 22, 2022, 9:44:58 AM11/22/22
to Harbour Users
Hi guys and many thanks for answers.

>May be it is a solution for you...
>
>Regards,
>Grigory

Many thanks Grigory, I'm trying your code and works like a charms.
I try this
? hb_NtoC( VAL( ld_str( ld_set( decPart ), 8 ) ) ) ==> 0.0001 :-))

At this point, this observation comes to my mind: having to perform mathematical operations involving real float numbers (e.g. conversion of u.m. , transformations of matrix, sine, cosine, etc. e.g. to paint PDF) using XBase variables, I will have a certain degree of error in the calculations due to the internal Xbase/Harbour number handling.
iow decPart (without your code) used will be 0.0001 (see hb_NtoS) or 0.00009999999999998899 (see hb_NtoC) ?
Using your functions (see my test) it seems 0.0001.

Anyway, many thanks.
Luigi

jgt

unread,
Jan 18, 2023, 10:18:10 AM1/18/23
to Harbour Users
I develop using both Harbour and Gnucobol.  Both translate source code into C and then compile the C to create an executable.
Gnucobol uses the GMPLIB  library for arithmetic.  Not being a C programmer, I have no idea of the work involved to incorporate this library.
Reply all
Reply to author
Forward
0 new messages