Math Processor Unit Library

libmpu – library of arithmetic functions for integer, real, and complex numbers of increased digit capacity

16 Commits   0 Branches   2 Tags

/***************************************************************
  __MPU_IOREAL.C

       This file contains source code of functions for
       REAL input/output operations.

       PART OF : MPU - library .

       USAGE   : Internal only .

       NOTE    : NONE .

       Copyright (C) 2000 - 2024  by Andrew V.Kosteltsev.
       All Rights Reserved.
 ***************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>   /* errno(3)  */
#include <string.h>  /* strcpy(3) */
#include <strings.h> /* bzero(3)  */
#include <stdlib.h>

#include <libmpu.h>
#include <mpu-context.h>

#include <mpu-emutype.h>
#include <mpu-integer.h>
#include <mpu-real.h>
#include <mpu-floatp.h>
#include <mpu-ioreal.h>

#include <mpu-char.h>
#include <mpu-symbols.h>

#include <mpu-math-errno.h>
#include <mpu-mtherr.h>


#define NTEN_128      28
#define NTEN_256      28

#define NTEN_512      60
#define NTEN_1024     60

#define NTEN_2048    124
#define NTEN_4096    124

#define NTEN_8192    252
#define NTEN_16384   252

#define NTEN_32768   508
#define NTEN_65536   508

#define NTEN_131072 1020


static int _get_nten( int nb )
{
  int  rc = 0;

  if( nb < NBR_32 || nb > MPU_REAL_IO_LIMIT )
  {
    /* error: Invalid size of operand(s) */
    __real_error_no = __R_ESIZE__;
    __STIND; /* Set REAL ind-produsing operation Flag */
    return( rc );
  }

  switch( nb )
  {
    case NBR_32   :
    case NBR_64   :
    case NBR_128  :
       rc = NTEN_128;
       break;
    case NBR_256  :
       rc = NTEN_256;
       break;
    case NBR_512  :
       rc = NTEN_512;
       break;
    case NBR_1024 :
       rc = NTEN_1024;
       break;
    case NBR_2048 :
       rc = NTEN_2048;
       break;
    case NBR_4096 :
       rc = NTEN_4096;
       break;
    case NBR_8192 :
       rc = NTEN_8192;
       break;
    case NBR_16384:
       rc = NTEN_16384;
       break;
    case NBR_32768:
       rc = NTEN_32768;
       break;
    case NBR_65536:
       rc = NTEN_65536;
       break;

    default:
    {
       /* error: Invalid size of operand(s) */
       __real_error_no = __R_ESIZE__;
       __STIND; /* Set REAL ind-produsing operation Flag */
       break;
    }

  } /* End of switch( nb ) */

  return( rc );

} /* End of _get_nten() */


/***************************************************************
  Кодировка имен файлов:

  Трехзначное десятичное число, представляющее количество
  128-и битных слов, из которых состоят вещественные числа
  размещенные в массивах:

    размер чисел в битах  кодировка
    --------------------  ---------
                     128  001
                     256  002
                     512  004
                    1024  008
                    2048  016
                    4096  032
                    8192  064
                   16384  128
                   32768  256
                   65536  512 (это предел);

    ПРИМЕРЫ:
    -------
      ei_mtens_001_emu32lsb.dfn -   128-бит,
      ei_mtens_512_emu32lsb.dfn - 65536-бит.

 ***************************************************************/

#if MPU_REAL_IO_LIMIT >= 128
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu00128/ei_mtens_001_emu32lsb.dfn>
#include <etens/emu00128/ei_ptens_001_emu32lsb.dfn>
#else
#include <etens/emu00128/ei_mtens_001_emu32msb.dfn>
#include <etens/emu00128/ei_ptens_001_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 128 */

#if MPU_REAL_IO_LIMIT >= 256
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu00256/ei_mtens_002_emu32lsb.dfn>
#include <etens/emu00256/ei_ptens_002_emu32lsb.dfn>
#else
#include <etens/emu00256/ei_mtens_002_emu32msb.dfn>
#include <etens/emu00256/ei_ptens_002_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 256 */

#if MPU_REAL_IO_LIMIT >= 512
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu00512/ei_mtens_004_emu32lsb.dfn>
#include <etens/emu00512/ei_ptens_004_emu32lsb.dfn>
#else
#include <etens/emu00512/ei_mtens_004_emu32msb.dfn>
#include <etens/emu00512/ei_ptens_004_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 512 */

#if MPU_REAL_IO_LIMIT >= 1024
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu01024/ei_mtens_008_emu32lsb.dfn>
#include <etens/emu01024/ei_ptens_008_emu32lsb.dfn>
#else
#include <etens/emu01024/ei_mtens_008_emu32msb.dfn>
#include <etens/emu01024/ei_ptens_008_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 1024 */

#if MPU_REAL_IO_LIMIT >= 2048
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu02048/ei_mtens_016_emu32lsb.dfn>
#include <etens/emu02048/ei_ptens_016_emu32lsb.dfn>
#else
#include <etens/emu02048/ei_mtens_016_emu32msb.dfn>
#include <etens/emu02048/ei_ptens_016_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 2048 */

#if MPU_REAL_IO_LIMIT >= 4096
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu04096/ei_mtens_032_emu32lsb.dfn>
#include <etens/emu04096/ei_ptens_032_emu32lsb.dfn>
#else
#include <etens/emu04096/ei_mtens_032_emu32msb.dfn>
#include <etens/emu04096/ei_ptens_032_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 4096 */

#if MPU_REAL_IO_LIMIT >= 8192
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu08192/ei_mtens_064_emu32lsb.dfn>
#include <etens/emu08192/ei_ptens_064_emu32lsb.dfn>
#else
#include <etens/emu08192/ei_mtens_064_emu32msb.dfn>
#include <etens/emu08192/ei_ptens_064_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 8192 */

#if MPU_REAL_IO_LIMIT >= 16384
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu16384/ei_mtens_128_emu32lsb.dfn>
#include <etens/emu16384/ei_ptens_128_emu32lsb.dfn>
#else
#include <etens/emu16384/ei_mtens_128_emu32msb.dfn>
#include <etens/emu16384/ei_ptens_128_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 16384 */

#if MPU_REAL_IO_LIMIT >= 32768
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu32768/ei_mtens_256_emu32lsb.dfn>
#include <etens/emu32768/ei_ptens_256_emu32lsb.dfn>
#else
#include <etens/emu32768/ei_mtens_256_emu32msb.dfn>
#include <etens/emu32768/ei_ptens_256_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 32768 */

#if MPU_REAL_IO_LIMIT >= 65536
#if MPU_WORD_ORDER_BIG_ENDIAN == 0
#include <etens/emu65536/ei_mtens_512_emu32lsb.dfn>
#include <etens/emu65536/ei_ptens_512_emu32lsb.dfn>
#else
#include <etens/emu65536/ei_mtens_512_emu32msb.dfn>
#include <etens/emu65536/ei_ptens_512_emu32msb.dfn>
#endif
#endif /* MPU_REAL_IO_LIMIT >= 65536 */


static EMUSHORT *_get_tens_ptr( int nb )
{
  EMUSHORT *rc = (EMUSHORT *)NULL;

  if( nb < NBR_32 || nb > MPU_REAL_IO_LIMIT )
  {
    /* error: Invalid size of operand(s) */
    __real_error_no = __R_ESIZE__;
    __STIND; /* Set REAL ind-produsing operation Flag */
    return( rc );
  }

  switch( nb )
  {
#if MPU_REAL_IO_LIMIT >= 128
    case NBR_32   :
    case NBR_64   :
    case NBR_128  :
      rc =   (EMUSHORT *)&_ei_tens_128_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 128 */
#if MPU_REAL_IO_LIMIT >= 256
    case NBR_256  :
      rc =   (EMUSHORT *)&_ei_tens_256_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 256 */
#if MPU_REAL_IO_LIMIT >= 512
    case NBR_512  :
      rc =   (EMUSHORT *)&_ei_tens_512_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 512 */
#if MPU_REAL_IO_LIMIT >= 1024
    case NBR_1024 :
      rc =  (EMUSHORT *)&_ei_tens_1024_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 1024 */
#if MPU_REAL_IO_LIMIT >= 2048
    case NBR_2048 :
      rc =  (EMUSHORT *)&_ei_tens_2048_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 2048 */
#if MPU_REAL_IO_LIMIT >= 4096
    case NBR_4096 :
      rc =  (EMUSHORT *)&_ei_tens_4096_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 4096 */
#if MPU_REAL_IO_LIMIT >= 8192
    case NBR_8192 :
      rc =  (EMUSHORT *)&_ei_tens_8192_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 8192 */
#if MPU_REAL_IO_LIMIT >= 16384
    case NBR_16384:
      rc = (EMUSHORT *)&_ei_tens_16384_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 16384 */
#if MPU_REAL_IO_LIMIT >= 32768
    case NBR_32768:
      rc = (EMUSHORT *)&_ei_tens_32768_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 32768 */
#if MPU_REAL_IO_LIMIT >= 65536
    case NBR_65536:
      rc = (EMUSHORT *)&_ei_tens_65536_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 65536 */

    default:
    {
      /* error: Invalid size of operand(s) */
      __real_error_no = __R_ESIZE__;
      __STIND; /* Set REAL ind-produsing operation Flag */
      break;
    }

  } /* End of switch( nb ) */

  return( rc );

} /* End of _get_tens_ptr() */


static EMUSHORT *_get_mtens_ptr( int nb )
{
  EMUSHORT *rc = (EMUSHORT *)NULL;

  if( nb < NBR_32 || nb > MPU_REAL_IO_LIMIT )
  {
    /* error: Invalid size of operand(s) */
    __real_error_no = __R_ESIZE__;
    __STIND; /* Set REAL ind-produsing operation Flag */
    return( rc );
  }

  switch( nb )
  {
#if MPU_REAL_IO_LIMIT >= 128
    case NBR_32   :
    case NBR_64   :
    case NBR_128  :
      rc =   (EMUSHORT *)&_ei_mtens_128_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 128 */
#if MPU_REAL_IO_LIMIT >= 256
    case NBR_256  :
      rc =   (EMUSHORT *)&_ei_mtens_256_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 256 */
#if MPU_REAL_IO_LIMIT >= 512
    case NBR_512  :
      rc =   (EMUSHORT *)&_ei_mtens_512_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 512 */
#if MPU_REAL_IO_LIMIT >= 1024
    case NBR_1024 :
      rc =  (EMUSHORT *)&_ei_mtens_1024_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 1024 */
#if MPU_REAL_IO_LIMIT >= 2048
    case NBR_2048 :
      rc =  (EMUSHORT *)&_ei_mtens_2048_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 2048 */
#if MPU_REAL_IO_LIMIT >= 4096
    case NBR_4096 :
      rc =  (EMUSHORT *)&_ei_mtens_4096_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 4096 */
#if MPU_REAL_IO_LIMIT >= 8192
    case NBR_8192 :
      rc =  (EMUSHORT *)&_ei_mtens_8192_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 8192 */
#if MPU_REAL_IO_LIMIT >= 16384
    case NBR_16384:
      rc = (EMUSHORT *)&_ei_mtens_16384_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 16384 */
#if MPU_REAL_IO_LIMIT >= 32768
    case NBR_32768:
      rc = (EMUSHORT *)&_ei_mtens_32768_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 32768 */
#if MPU_REAL_IO_LIMIT >= 65536
    case NBR_65536:
      rc = (EMUSHORT *)&_ei_mtens_65536_[0][0];
      break;
#endif /* MPU_REAL_IO_LIMIT >= 65536 */

    default:
    {
      /* error: Invalid size of operand(s) */
      __real_error_no = __R_ESIZE__;
      __STIND; /* Set REAL ind-produsing operation Flag */
      break;
    }

  } /* End of switch( nb ) */

  return( rc );

} /* End of _get_mtens_ptr() */


/***************************************************************
  SEE: __MPU_FLOATP.H for definitions REAL_xxxxxx__MAX_STRING
 ***************************************************************/

#define MAX_STRING_SIZE(n)   REAL_##n##_MAX_STRING

#if MPU_REAL_IO_LIMIT == 32
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(32)
#else
#if MPU_REAL_IO_LIMIT == 64
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(64)
#else
#if MPU_REAL_IO_LIMIT == 128
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(128)
#else
#if MPU_REAL_IO_LIMIT == 256
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(256)
#else
#if MPU_REAL_IO_LIMIT == 512
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(512)
#else
#if MPU_REAL_IO_LIMIT == 1024
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(1024)
#else
#if MPU_REAL_IO_LIMIT == 2048
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(2048)
#else
#if MPU_REAL_IO_LIMIT == 4096
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(4096)
#else
#if MPU_REAL_IO_LIMIT == 8192
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(8192)
#else
#if MPU_REAL_IO_LIMIT == 16384
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(16384)
#else
#if MPU_REAL_IO_LIMIT == 32768
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(32768)
#else
#if MPU_REAL_IO_LIMIT == 65536
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(65536)
#else
#if MPU_REAL_IO_LIMIT == 131072
#define REAL_MAX_STRING_SIZE    MAX_STRING_SIZE(131072)
#else
#error mpu-ioreal.c: Failed value of MPU_REAL_IO_LIMIT (use: 32,64, ..., 131072)
#endif /* MPU_REAL_IO_LIMIT == 131072 */
#endif /* MPU_REAL_IO_LIMIT ==  65536 */
#endif /* MPU_REAL_IO_LIMIT ==  32768 */
#endif /* MPU_REAL_IO_LIMIT ==  16384 */
#endif /* MPU_REAL_IO_LIMIT ==   8192 */
#endif /* MPU_REAL_IO_LIMIT ==   4096 */
#endif /* MPU_REAL_IO_LIMIT ==   2048 */
#endif /* MPU_REAL_IO_LIMIT ==   1024 */
#endif /* MPU_REAL_IO_LIMIT ==    512 */
#endif /* MPU_REAL_IO_LIMIT ==    256 */
#endif /* MPU_REAL_IO_LIMIT ==    128 */
#endif /* MPU_REAL_IO_LIMIT ==     64 */
#endif /* MPU_REAL_IO_LIMIT ==     32 */


void ei_real_to_ascii( __mpu_char8_t *string, EMUSHORT *ei, int ndigs, int exp_delim, int exp_digs, int gen_plus, int nb )
/***************************************************************

 Description        : ei_real_to_ascii() Работает с
                                         internal e-type
                                         data struct.

 Concepts           : Convert internal e-type EI to ASCII
                      STRING with NDIGS digits after the
                      decimal point.
                      EXP_DELIM is char to delimited Exponent
                      in the output STRING, for example,
                      1.j+27.

 Use Global Variable:

 Use Functions      :
                      iitoa_np();                 | mpu-integer.c
                      internal_np( nb );          | mpu-real.c
                      internal_ne( nb );          | mpu-real.c
                      internal_ns( nb );          | mpu-real.c

 Parameters         :
                      __mpu_char8_t *string; - output string;
                      EMUSHORT          *ei; - указатель на
                                               internal e-type
                                               data struct;
                      int             ndigs; - количество цифр
                                               после десятичной
                                               точки;
                      int         exp_delim; - символ отделяющий
                                               ЭКСРОНЕНТУ;
                      int          exp_digs; - количество цифр
                                               экспоненты;
                      NOTE ====================================
                           В том случае, когда( exp_digs > 0 )
                           {
                             Если реальное количество цифр
                             меньше exp_digs, то экспонента
                             будет дополнена старшими
                             незначащими нулями.
                             Если реальное количество цифр
                             больше exp_digs, то экспонента
                             изменена не будет.
                           }
                      =========================================

                      int          gen_plus; - принудительная
                                               генерация знака
                                               плюс перед
                                               положтельным
                                               числом;
                      NOTE ====================================
                           В случае, когда( gen_plus != 0 )
                           {
                             При переводе положительного
                             числа в строку происходит
                             принудительная запись знака 
                             плюс перед числом в строке.
                           }
                           иначе
                           {
                             Положительное число печатается
                             как обычно (т.е. без знака).
                           }
                      =========================================

                      int                nb; - количество бит в
                                               external e-type
                                               data struct.

 Return             : [void]

 ***************************************************************/
{
  EMUSHORT          *n = NULL,
                    *m = NULL,
                *expon = NULL,
                *exone = NULL,
                  *inc = NULL,

                *equot = NULL,
                  *tmp = NULL,
                  *ten = NULL,
                    *y = NULL,
                    *t = NULL,
                    *u = NULL,
                    *w = NULL;
  EMUSHORT      *p, *r;
  EMUSHORT       sign;
  __mpu_int32_t  j, digit;
  int            rndsave, n_ten;
  int            jc, k;
  __mpu_char8_t *s, *ss, *t_string = NULL;
  int            np, ne, ns, i, ln, n_dec;


  errno = 0;

  if( nb < NBR_32 || nb > MPU_REAL_IO_LIMIT )
  {
    /* error: Invalid size of operand(s) */
    __real_error_no = __R_ESIZE__;
    __STIND; /* Set REAL ind-produsing operation Flag */
    return;
  }

  t_string = (__mpu_char8_t *)malloc(REAL_MAX_STRING_SIZE+1);
  if( !t_string )
  {
    /* fatal error */
    return;
  }

  rndsave = rndprc;
  ss  = string;
  s   = t_string;
  *ss = '\0';
  ln = _get_max_string( nb );
  for( i = 0; i < ln; i++ ) s[i] = '\0'; /* or bzero( s, ln ); */

  np = internal_np( nb );
  ne = internal_ne( nb );
  ns = internal_ns( nb );


  /*** Allocate memory for n, m, expon, exone, inc . **********/
  n = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !n )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    return;
  }

  m = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !m )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    __mpu_sbrk( -(int)((ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  expon = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !expon )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    __mpu_sbrk( -(int)(2*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  exone = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !exone )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    __mpu_sbrk( -(int)(3*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  inc = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !inc )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    __mpu_sbrk( -(int)(4*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }
  /************************************************************/

  /*** Allocate memory for equot, tmp, ten, y, t, u, w . ******/
  equot = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !equot )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  tmp = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !tmp )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE equot *************/
    __mpu_sbrk( -(int)(np*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  ten = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !ten )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE equot *************/
    /* FREE tmp ***************/
    __mpu_sbrk( -(int)(2*np*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  y = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !y )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE equot *************/
    /* FREE tmp ***************/
    /* FREE ten ***************/
    __mpu_sbrk( -(int)(3*np*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  t = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !t )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE equot *************/
    /* FREE tmp ***************/
    /* FREE ten ***************/
    /* FREE y *****************/
    __mpu_sbrk( -(int)(4*np*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  u = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !u )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE equot *************/
    /* FREE tmp ***************/
    /* FREE ten ***************/
    /* FREE y *****************/
    /* FREE t *****************/
    __mpu_sbrk( -(int)(5*np*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }

  w = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !w )
  {
    /* fatal error */

    /* FREE t_string **********/
    free( t_string );
    /**************************/

    /* FREE n *****************/
    /* FREE m *****************/
    /* FREE expon *************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE equot *************/
    /* FREE tmp ***************/
    /* FREE ten ***************/
    /* FREE y *****************/
    /* FREE t *****************/
    /* FREE u *****************/
    __mpu_sbrk( -(int)(6*np*SIZE_OF_EMUSHORT) );
    /**************************/

    return;
  }
  /************************************************************/



  n_dec = _get_ndec( nb );
  n_ten = _get_nten( nb );

  if( nb > NBR_64 )
    n_dec -= 1; /* Необходимо для правильного округления мантиссы */

  if( ei_isind( ei, nb ) )
  {
    strncpy( t_string, " -ind", 6 ); /* " -1.#IND00"; */

    if( exp_delim == 'r' || exp_delim == 'R' )
    {
      strcat( t_string, "_r" );
    }
    else if( exp_delim == 'j' || exp_delim == 'J' )
    {
      strcat( t_string, "_j" );
    }
    goto bxit;
  }

  if( ei_isnans( ei, nb ) )
  {
    if( ei_isneg( ei, nb ) ) strncpy( t_string, " -", 3 );
    else if( gen_plus )      strncpy( t_string, " +", 3 );
         else                strncpy( t_string, " ",  2 ); /* + */
    strcat( t_string, "NaN" ); /* "1.#QNAN0"; */

    if( exp_delim == 'r' || exp_delim == 'R' )
    {
      strcat( t_string, "_r" );
    }
    else if( exp_delim == 'j' || exp_delim == 'J' )
    {
      strcat( t_string, "_j" );
    }
    goto bxit;
  }

  rndprc = (int)NSBITS(nb); /* Set to full precision */
  ei_copy( y, ei, nb );

  /* Save Sign */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  if( y[0] )
#else
  if( y[ns + ne + 2] )
#endif
  {
    sign = MASK_ALL_BITS;
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    y[0]           = (EMUSHORT)0; /* Clear sign */
#else
    y[ns + ne + 2] = (EMUSHORT)0; /* Clear sign */
#endif
  }
  else
  {
    sign =  (EMUSHORT)0;
  }

  /* expon = 0 */
  for( i = 0; i < ne+1; i++ ) expon[i] = (EMUSHORT)0;

  /* ten = 1.0E1 */
  _gen_ten( ten, nb );

  /* t = 1.0E0 */
  _gen_one( t, nb );

  /* Gen EXONE */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  /* hight part */
  p = exone;
  *p++ = (EMUSHORT)0;
  *p++ = HIGHT_EXONE; /* 0x3fff... */
  for( i = 0; i < ne - 1; i++ ) *p++ = MASK_ALL_BITS;
#else
  /* hight part */
  p = exone + ne;
  *p-- = (EMUSHORT)0;
  *p-- = HIGHT_EXONE;
  for( i = 0; i < ne - 1; i++ ) *p-- = MASK_ALL_BITS;
#endif


  /**************************
    Test for zero Exponent
   **************************/
  /* Copy Exponents */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  ei_cpye_unpack( inc, &y[1],    ne+1, ne );
#else
  ei_cpye_unpack( inc, &y[ns+2], ne+1, ne );
#endif
  if( ei_cmp0e( inc, ne+1 ) == 0 ) /* Exponent == 0 */
  {
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    for( i = ne+2; i < np-1; i++ )
#else
    for( i = 1; i < ns+1; i++ )
#endif
    {
      if( y[i] != (EMUSHORT)0 )
        goto tnzero; /* Denormalized number */
    }
    goto isone;        /* Valid all zeros */
  } /* End if( Exponent == 0 ) */

tnzero:

  /*********************
    Test for infinity
   *********************/
  if( ei_isinfin( y, nb ) )
  {
    if( sign )          strncpy( t_string, " -inf", 6 ); /* " -1.#INF00"; */
    else if( gen_plus ) strncpy( t_string, " +inf", 6 ); /* " +1.#INF00"; */
         else           strncpy( t_string, " inf",  5 );  /* " 1.#INF00"; */

    if( exp_delim == 'r' || exp_delim == 'R' )
    {
      strcat( t_string, "_r" );
    }
    else if( exp_delim == 'j' || exp_delim == 'J' )
    {
      strcat( t_string, "_j" );
    }
    goto bxit;

  } /* End of Infin */

  /**********************************************************
    Test for Exponent nonzero but Significand denormalized.
    This is an ERROR condition.
   **********************************************************/
  if( (ei_cmp0e( inc, ne+1 ) != 0) &&
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
     ((y[ne+2] & MASK_SIGN) == 0) )
#else
     ((y[ns]   & MASK_SIGN) == 0) )
#endif
  {
    /* "domain error" */
    errno = __mpu_math_errnotab[__DOMAIN__];
    __STDOM; /* Set REAL Domain Flag */
    strncpy( t_string, "NaN", 4 ); /* "1.#QNAN0"; */

    if( exp_delim == 'r' || exp_delim == 'R' )
    {
      strcat( t_string, "_r" );
    }
    else if( exp_delim == 'j' || exp_delim == 'J' )
    {
      strcat( t_string, "_j" );
    }
    goto bxit;
  }

  /******************
    Compare to 1.0
   ******************/
  jc = ei_cmp( t, y, nb );
  if( jc == 0 ) goto isone;

  if( jc == -2 )
  {
    /* abort() */
    strncpy( string, " -ind", 6 ); /* " -1.#IND00"; */

    if( exp_delim == 'r' || exp_delim == 'R' )
    {
      strcat( t_string, "_r" );
    }
    else if( exp_delim == 'j' || exp_delim == 'J' )
    {
      strcat( t_string, "_j" );
    }
    /* abort() */
  }

  if( jc < 0 ) /* Number is greater than 1 (y > 1.0) */
  {
    ei_copy( u, y, nb );

    /* u[Exponent] = EXONE + NSBITS - 1 */
    j = (EMUSHORT)NSBITS(nb);
    j -= 1;
    ei_cvte_unpack( inc, (EMUSHORT *)&j, ne+1, 1 );
    ei_adde( inc, exone, inc, ne+1 );
    /* Copy Exponents */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    ei_cpye_pack( &u[1],    inc,  ne, ne+1 );
#else
    ei_cpye_pack( &u[ns+2], inc,  ne, ne+1 );
#endif

    p = _get_tens_ptr( nb );

    /* if( BITS_PER_EMUSHORT == 16 ) { *p = 10**16; } */
    /* if( BITS_PER_EMUSHORT == 32 ) { *p = 10**32; } */
    /* if( BITS_PER_EMUSHORT == 64 ) { *p = 10**64; } */
    p += np*(n_ten-POW2); /* -POW2 see: mpu-emutype.h */

    j = BITS_PER_EMUSHORT;
    ei_cvte_unpack( m, (EMUSHORT *)&j, ne+1, 1 ); /* m = BITS_PER_EMUSHORT; */

    do
    {
      ei_div( t, u, p, nb );
      ei_floor( w, t, nb );
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
      for( i = ne+2; i < np-1; i++ )
#else
      for( i = 1; i < ns+1; i++ )
#endif
      {
        if( t[i] != w[i] ) goto noint;
      }
      ei_copy( u, t, nb );
      ei_adde( expon, expon, m, ne+1 );
noint:
      p += np;
      ei_shrn( m, m, (unsigned)1, ne+1 ); /* m >>= 1 */

    } while( ei_cmp0e( m, ne+1 ) != 0 );

    /* Rescale from integer Significand */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    ei_cpye_unpack( m, &y[1],    ne+1, ne );
#else
    ei_cpye_unpack( m, &y[ns+2], ne+1, ne );
#endif

#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    ei_cpye_unpack( n, &u[1],    ne+1, ne );
#else
    ei_cpye_unpack( n, &u[ns+2], ne+1, ne );
#endif

    /* inc еще равно EXONE + NSBITS - 1 */
    ei_sube( m, m, inc, ne+1 );
    ei_adde( n, n, m, ne+1 );

#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    ei_cpye_pack( &u[1],    n,  ne, ne+1 );
#else
    ei_cpye_pack( &u[ns+2], n,  ne, ne+1 );
#endif
    /* т.е. u[exp] += y[exp] -(unsigned)(EXONE + NBITS - 1) */

    ei_copy( y, u, nb );

    /* Find power of 10 */
    /* t = 1.0E0 */
    _gen_one( t, nb );

    /* m = MAXP */
    for( i = 0; i < ne+1; i++ ) m[i] = (EMUSHORT)0;
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    m[1]    = HIGHT_EXMAX_P;
#else
    m[ne-1] = HIGHT_EXMAX_P;
#endif

    p = _get_tens_ptr( nb );
    /* An unordered compare result shouldn't happen here */
    while( ei_cmp( ten, u, nb ) <= 0 )
    {
      if( ei_cmp( p, u, nb ) <= 0 )
      {
        ei_div( u, u, p, nb );
        ei_mul( t, t, p, nb );
        ei_adde( expon, expon, m, ne+1 );

      } /* End if( p <= u ) */

      ei_shrn( m, m, (unsigned)1, ne+1 ); /* m >>= 1 */
      if( ei_cmp0e( m, ne+1 ) == 0 ) break;
      p += np;

    } /* End of while( ten <= u ) */

  }
  else        /* Number is less than 1 (y < 1.0) */
  {

    /* tmp = 1.0E0 */
    _gen_one( tmp, nb );

    /* Pad Significand with trailing decimal zeros */
    /* Test for zero Exponent */
    /* Copy Exponents */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    ei_cpye_unpack( inc, &y[1],    ne+1, ne );
#else
    ei_cpye_unpack( inc, &y[ns+2], ne+1, ne );
#endif
    if( ei_cmp0e( inc, ne+1 ) == 0 ) /* Exponent == 0 */
    {
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
      while( (y[ne+2] & MASK_SIGN) == 0 )
#else
      while( (y[ns]   & MASK_SIGN) == 0 )
#endif
      {
        ei_mul( y, y, ten, nb );
        ei_dece( expon, expon, ne+1 ); /* expon -= 1; */
      }
    }
    else /* Exponent != 0 */
    {
      ei_copy( w, y, nb );
      for( i = 0; i < n_dec + 1; i++ )
      {
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
        if( (w[ne+ns+2] & 0x7) != 0 ) /* lgw */
#else
        if( (w[0]       & 0x7) != 0 ) /* lgw */
#endif
           break;

        /* multiply by 10 */
        ei_copyzlgw( u, w, nb );
        ei_shdown( u, (unsigned)2, nb );
        ei_addm( u, w, u, nb );

        j = 3; /* Exponent += 3 */
        ei_cvte_unpack( inc, (EMUSHORT *)&j, ne, 1 );
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
        ei_adde( &u[1],    &u[1],    inc, ne );
#else
        ei_adde( &u[ns+2], &u[ns+2], inc, ne );
#endif

#if MPU_WORD_ORDER_BIG_ENDIAN == 1
        while( u[ne+1] != (EMUSHORT)0 ) /* hgw != 0 */
#else
        while( u[ns+1] != (EMUSHORT)0 ) /* hgw != 0 */
#endif
        {
           ei_shdown( u, (unsigned)1, nb );
           /* Exponent += 1 */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
           ei_ince( &u[1],    &u[1],    ne );
#else
           ei_ince( &u[ns+2], &u[ns+2], ne );
#endif
        }
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
        if( u[ne+ns+2] != (EMUSHORT)0 ) /* lgw != 0 */
#else
        if( u[0]       != (EMUSHORT)0 ) /* lgw != 0 */
#endif
           break;

#if MPU_WORD_ORDER_BIG_ENDIAN == 1
        if( ei_cmpe( &tmp[1],    &u[1],    ne ) <= 0 )
#else
        if( ei_cmpe( &tmp[ns+2], &u[ns+2], ne ) <= 0 )
#endif
           break;

        ei_copyzlgw( w, u, nb );
        ei_dece( expon, expon, ne+1 ); /* expon -= 1; */

      } /* End for( i < n_dec ) */

      ei_copy( y, w, nb );

    } /* Enf if( y[Exponent] == 0 ) */

    /* m = - MAXP */
    for( i = 0; i < ne+1; i++ ) m[i] = (EMUSHORT)0;
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    m[1]    = HIGHT_EXMAX_P;
#else
    m[ne-1] = HIGHT_EXMAX_P;
#endif

    p = _get_mtens_ptr( nb );
    r = _get_tens_ptr( nb );

    ei_copy( w, y, nb );
    ei_copy( t, tmp, nb ); /* t = 1.0 */

    while( ei_cmp( tmp, w, nb ) > 0 )
    {
      if( ei_cmp( p, w, nb ) >= 0 )
      {
        ei_mul( w, w, r, nb );
        ei_mul( t, t, r, nb );
        ei_sube( expon, expon, m, ne+1 ); /* expon -= m; */
      }
      ei_shrn( m, m, (unsigned)1, ne+1 ); /* m /= 2; */

      if( ei_cmp0e( m, ne+1 ) == 0 ) break;

      p += np;
      r += np;
    }

    ei_div( t, tmp, t, nb ); /* t = 1.0 / t; */

  }

isone:

  /* Find the first (leading) digit */
  ei_copy( w, t, nb );
  ei_copyzlgw( t, w, nb );
  ei_copy( w, y, nb );
  ei_copyzlgw( y, w, nb );

  ei_remain( y, equot, y, t, nb );

#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  digit = equot[ne+ns+2]; /* lgw */
#else
  digit = equot[0];       /* lgw */
#endif

  /* tmp = 0E0 */
  _gen_zero( tmp, nb );

  while( (digit == 0) && (ei_cmp( y, tmp, nb ) != 0) )
  {
    ei_shup( y, (unsigned)1, nb );
    ei_copyzlgw( u, y, nb );
    ei_shup( u, (unsigned)2, nb );
    ei_addm( y, y, u, nb );
    ei_remain( y, equot, y, t, nb );
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    digit = equot[ne+ns+2]; /* lgw */
#else
    digit = equot[0];       /* lgw */
#endif
    ei_dece( expon, expon, ne+1 ); /* expon -= 1; */
  }

  s = t_string;

  if( sign ) *s++ = '-';
  else if( gen_plus )   *s++ = '+';
       else             *s++ = ' ';

  /* Examine number of digits requested by caller */
  if( ndigs < 0 )     ndigs = 0;
  if( ndigs > n_dec ) ndigs = (int)n_dec;

  if( digit == 10 )
  {
    *s++ = '1';
    *s++ = '.';
    if( ndigs > 0 )
    {
      *s++ = '0';
      ndigs -= 1;
    }
    ei_ince( expon, expon, ne+1 ); /* expon += 1; */
  }
  else
  {
    *s++ = (__mpu_char8_t)digit + '0';
    *s++ = '.';
  }

  /* Generate digits after the decimal point */
  for( k = 0; k <= ndigs; k++ )
  {
    ei_shup( y, (unsigned)1, nb );
    ei_copyzlgw( u, y, nb );
    ei_shup( u, (unsigned)2, nb );
    ei_addm( y, u, y, nb );
    ei_remain( y, equot, y, t, nb );
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    *s++ = (__mpu_char8_t)equot[ne+ns+2] + '0'; /* lgw */
#else
    *s++ = (__mpu_char8_t)equot[0]       + '0'; /* lgw */
#endif
  }

#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  digit = equot[ne+ns+2]; /* lgw */
#else
  digit = equot[0];       /* lgw */
#endif

  --s;
  ss = s;

  /* Round off the ASCII string */
  if( digit > 4 )
  {
    /* Test for critical rounding case in ASCII output */
    if( digit == 5 )
    {
      ei_copy( t, y, nb );
      if( ei_cmp( t, tmp, nb ) != 0 ) goto roun;  /* round to nearest */
      if( (*(s - 1) & 1) == 0 )       goto doexp; /* round to even */

    } /* End if( digit == 5 ) */

    /* Round up and propagate carry-outs */
roun:
    --s;
    k = *s & 0x7f;
    /* Carry out to most significant digit? */
    if( k == '.' )
    {
      --s;
      k = *s;
      k += 1;
      *s = (__mpu_char8_t)k;

      /* Most significant digit carries to 10? */
      if( k > '9' )
      {
        ei_ince( expon, expon, ne+1 ); /* expon += 1; */
        *s = '1';
      }
      goto doexp;
    }

    /* Round up and carry out from less significant digits */
    k += 1;
    *s = (__mpu_char8_t)k;
    if( k > '9' )
    {
      *s = '0';
      goto roun;
    }

  } /* Enf if( digit > 4 ) */

doexp:
  {
    __mpu_char8_t  sexp[512];
    __mpu_char8_t  sexd[4];

    /* Не изменяет флаги: CF, AF, PF, ZF, SF, OF, RF. */
    iitoa_np( sexp,
              expon,
              10, /* radix */
              0,  /* upper flag */
              ne+1 );
    if( exp_digs > 0 )
    {
      /*************************************************
        Если это необходимо, недостающие цифры Exponent
        будут поставлены как старшие незначащие нули.
       *************************************************/
      __mpu_char8_t  stmp[512], *ptr;
      int            i, len;

      ptr = sexp;
      if( *ptr == '-' ) ptr++; /* skip sign */

      len = strlen( ptr );
      if( len < exp_digs )
      {
        strcpy( stmp, ptr );
        len = exp_digs - len;
        for( i = 0; i < len; i++ ) *ptr++ = '0';
        *ptr = '\0';
        strcat( sexp, stmp );

      } /* End if( len < exp_digs ) */

    } /* End if( exp_digs > 0 ) */

    if( ei_cmp0e( expon, ne+1 ) >= 0 )
    {
      /* Don't use sprintf() */
      sexd[0] = (__mpu_char8_t)exp_delim;
      sexd[1] = '+';
      sexd[2] = '\0';
    }
    else
    {
      /* Don't use sprintf() */
      sexd[0] = (__mpu_char8_t)exp_delim;
      sexd[1] = '\0';
    }

    strcpy( ss, sexd ); /* exp_delim */
    strcat( ss, sexp );
  }

bxit:
  rndprc = rndsave;
  /* Copy out the working string */
  s  = string;
  ss = t_string;
  while( *ss == ' ' ) ++ss; /* Strip possible leading space */
  while( (*s++ = *ss++) != '\0' )
    ;

  /* FREE t_string **********/
  free( t_string );
  /**************************/

  /* FREE n *****************/
  /* FREE m *****************/
  /* FREE expon *************/
  /* FREE exone *************/
  /* FREE inc ***************/
  __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
  /**************************/

  /* FREE equot *************/
  /* FREE tmp ***************/
  /* FREE ten ***************/
  /* FREE y *****************/
  /* FREE t *****************/
  /* FREE u *****************/
  /* FREE w *****************/
  __mpu_sbrk( -(int)(7*np*SIZE_OF_EMUSHORT) );
  /**************************/

} /* End of ei_real_to_ascii() */


int ei_ascii_to_real( EMUSHORT *ei, __mpu_char8_t *ss, int nb )
/***************************************************************

 Description        : ei_ascii_to_real() Работает с
                                         internal e-type data
                                         struct.

 Concepts           : Convert ASCII string SS to internal
                      e-type EI.

                      Return Code:
                      -1 (ASCII_TO_REAL_ERROR)  - read error;
                       0 (LONGHAND_REAL_NUMBER) - прочитано простое
                                                  число (типа 1e1);
                       1 (REAL_PART_OF_COMPLEX) - прочитана
                                                  вещественная часть
                                                  комплексного числа
                                                  (типа 1r1);
                       2 (IMAGINARY_OF_COMPLEX) - прочитана мнимая
                                                  часть комплексного
                                                  числа
                                                  (типа 1j1);
                      NOTE:
                      ====
                        Количество цифр, после десятичной точки,
                        не должно превышать величины
                        REAL_nnnn_MDEC_DIG + 1 (см.: mpu-floatp.h).

 Use Global Variable:

 Use Functions      :
                      internal_np( nb );          | mpu-real.c
                      internal_ne( nb );          | mpu-real.c
                      internal_ns( nb );          | mpu-real.c

 Parameters         :
                      EMUSHORT          *ei; - указатель на
                                               internal e-type
                                               data struct;
                      __mpu_char8_t     *ss; - input string;
                      int                nb; - количество бит в
                                               external e-type
                                               data struct.

 Return             : int                rc; - Return Code.

                      if( exp_delim == ('e' || 'E') ) rc =  0;
                      if( exp_delim == ('r' || 'R') ) rc =  1;
                      if( exp_delim == ('j' || 'J') ) rc =  2;

                      error:                          rc = -1;

 ***************************************************************/
{
  EMUSHORT       *nexp = NULL,
                 *lexp = NULL,
                 *dexp = NULL,
                  *exp = NULL,
                *exone = NULL,
                  *inc = NULL,

                   *yy = NULL,
                   *xt = NULL,
                   *tt = NULL;
  EMUSHORT       nsign, *p, *min_dexp, *max_dexp;
  __mpu_int32_t  j, jc;
  int            k, trail, c, rndsave, n_ten;
  int            esign, decflag, signflag, prec, lost;
  __mpu_char8_t *s, *sp, *lstr = NULL;
  int            rc     = ASCII_TO_REAL_ERROR,
                 type_r = LONGHAND_REAL_NUMBER;
  int            np, ne, ns, i;


  errno = 0;

  if( nb < NBR_32 || nb > MPU_REAL_IO_LIMIT )
  {
    /* error: Invalid size of operand(s) */
    __real_error_no = __R_ESIZE__;
    __STIND; /* Set REAL ind-produsing operation Flag */
    return( rc );
  }

  /* Copy the input string */
  lstr = (__mpu_char8_t *)malloc( strlen( ss ) + 1 );
  if( !lstr )
  {
    /* fatal error */
    return( rc );
  }
  s = ss;
  while( *s == ' ' ) ++s; /* Skip leading spaces */
  sp = lstr;
  while( (*sp++ = *s++) != '\0' )
    ;
  s = lstr;

  np = internal_np( nb );
  ne = internal_ne( nb );
  ns = internal_ns( nb );

  /*** Allocate memory for nexp, lexp, dexp, exp,
                        exone, inc . ***********************/
  nexp = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !nexp )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    return( rc );
  }

  lexp = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !lexp )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    __mpu_sbrk( -(int)((ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }

  dexp = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !dexp )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    /* FREE lexp **************/
    __mpu_sbrk( -(int)(2*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }

  exp = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !exp )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    /* FREE lexp **************/
    /* FREE dexp **************/
    __mpu_sbrk( -(int)(3*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }

  exone = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !exone )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    /* FREE lexp **************/
    /* FREE dexp **************/
    /* FREE exp ***************/
    __mpu_sbrk( -(int)(4*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }

  inc = (EMUSHORT *)__mpu_sbrk( (int)((ne+1)*SIZE_OF_EMUSHORT) );
  if( !inc )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    /* FREE lexp **************/
    /* FREE dexp **************/
    /* FREE exp ***************/
    /* FREE exone *************/
    __mpu_sbrk( -(int)(5*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }
  /************************************************************/

  /*** Allocate memory for yy, xt, tt . ***********************/
  yy = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !yy )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    /* FREE lexp **************/
    /* FREE dexp **************/
    /* FREE exp ***************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(6*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }

  xt = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !xt )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    /* FREE lexp **************/
    /* FREE dexp **************/
    /* FREE exp ***************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(6*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE yy ****************/
    __mpu_sbrk( -(int)(np*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }

  tt = (EMUSHORT *)__mpu_sbrk( (int)(np*SIZE_OF_EMUSHORT) );
  if( !tt )
  {
    /* fatal error */

    /* FREE lstr **************/
    free( lstr );
    /**************************/

    /* FREE nexp **************/
    /* FREE lexp **************/
    /* FREE dexp **************/
    /* FREE exp ***************/
    /* FREE exone *************/
    /* FREE inc ***************/
    __mpu_sbrk( -(int)(6*(ne+1)*SIZE_OF_EMUSHORT) );
    /**************************/

    /* FREE yy ****************/
    /* FREE xt ****************/
    __mpu_sbrk( -(int)(2*np*SIZE_OF_EMUSHORT) );
    /**************************/

    return( rc );
  }
  /************************************************************/

  /* Gen EXONE */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  /* hight part */
  p = exone;
  *p++ = (EMUSHORT)0;
  *p++ = HIGHT_EXONE; /* 0x3fff... */
  for( i = 0; i < ne - 1; i++ ) *p++ = MASK_ALL_BITS;
#else
  /* hight part */
  p = exone + ne;
  *p-- = (EMUSHORT)0;
  *p-- = HIGHT_EXONE;
  for( i = 0; i < ne - 1; i++ ) *p-- = MASK_ALL_BITS;
#endif


  rndsave = rndprc;
  if( nb == NBR_32 )      rndprc = 24;
  else if( nb == NBR_64 ) rndprc = 53;
       else               rndprc = (int)NSBITS( nb );

  lost     = 0;
  nsign    = (EMUSHORT)0;
  decflag  = 0;
  signflag = 0;
  prec     = 0;
  for( i = 0; i < ne+1; i++ ) nexp[i] = (EMUSHORT)0;
  for( i = 0; i < ne+1; i++ )  exp[i] = (EMUSHORT)0;
  ei_cleaz( yy, nb );
  trail    = 0;

nextcom:
  k = *s - '0';
  if( (k >= 0) && (k <= 9) )
  {
    /* Ignore leading zeros */
    if( (prec == 0) && (decflag == 0) && (k == 0) ) goto donchar;

    /* Identify and strip trailing zeros after the decimal point */
    if( (trail == 0) && (decflag != 0) )
    {
      sp = s;
      while( (*sp >= '0') && (*sp <= '9') ) ++sp;

      /* check for syntax error */
      c = *sp & 0x7f; /* Only ASCII code */
      if( (c != 'e')  && (c != 'E')  &&
          (c != 'r')  && (c != 'R')  &&
          (c != 'j')  && (c != 'J')  &&
          (c != '\n') && (c != '\r') &&
          (c != '\t') && (c != '\v') &&
          (c != '\0') &&
          (c != ' ')  && (c != ',') ) goto errors;
      --sp;
      while( *sp == '0' ) *sp-- = 'z';
      trail = 1;
      if( *s == 'z' ) goto donchar;

    } /* End if( trail == 0) && (decflag != 0) ) */

    /**************************************************************
      Продолжая пока не будет что-то записано в hgw, 
      мы гарантируем, что биты округления после нормализации
      будут выше lgw.
     **************************************************************/
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    if( yy[ne+1] == (EMUSHORT)0 ) /* hgw == 0 */
#else
    if( yy[ns+1] == (EMUSHORT)0 ) /* hgw == 0 */
#endif
    {
      /* Count digits after decimal point */
      if( decflag ) ei_ince( nexp, nexp, ne+1 );

      /* Multiply current number to 10 */
      ei_shup( yy, (unsigned)1, nb );
      ei_copyzlgw( xt, yy, nb );
      ei_shup( xt, (unsigned)2, nb );
      ei_addm( yy, xt, yy, nb );
      ei_cleaz( xt, nb );
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
      xt[ne+ns+1] = (EMUSHORT)k; /* low part of Significand */
#else
      xt[1]       = (EMUSHORT)k; /* low part of Significand */
#endif
      ei_addm( yy, xt, yy, nb );
    }
    else /* ( hgw != 0 ) */
    {
      /* Marc any lost non-zero digit */
      lost |= k;
      /* Count lost digits before the decimal point */
      if( decflag == 0 ) ei_dece( nexp, nexp, nb );

    } /* End if( hgw == 0 ) */

    prec += 1;
    goto donchar;

  } /* End if( (k >= 0) && (k <= 9) ) */

  switch( *s )
  {
    case 'z':
      break;

    case 'e':
    case 'E':
      goto exponent;
    case 'r':
    case 'R':
      type_r = REAL_PART_OF_COMPLEX;
      goto exponent;
    case 'j':
    case 'J':
      type_r = IMAGINARY_OF_COMPLEX;
      goto exponent;

    case '.': /* decimal point */
      if( decflag ) goto errors;
      ++decflag;
      break;

    case '-':
      nsign = MASK_ALL_BITS;
      if( signflag ) goto errors;
      /* Здесь можно пропустить пробелы между знаком и числом: */
      while( s[1] == ' '  ||
             s[1] == '\n' ||
             s[1] == '\r' ||
             s[1] == '\t' ||
             s[1] == '\v'    ) ++s;
      ++signflag;
      break;

    case '+':
      if( signflag ) goto errors;
      /* Здесь можно пропустить пробелы между знаком и числом: */
      while( s[1] == ' '  ||
             s[1] == '\n' ||
             s[1] == '\r' ||
             s[1] == '\t' ||
             s[1] == '\v'    ) ++s;
      ++signflag;
      break;

    case ',':
    case ' ':
    case '\0':
    case '\n':
    case '\r':
    case '\t':
    case '\v':
      goto daldone;

    case 'i':
    case 'I':
      /* ind ****************************************/
      if( (s[1] == 'n' || s[1] == 'N') &&
          (s[2] == 'd' || s[2] == 'D')   )
      {
        if( s[3] == '_' )
        {
          switch( s[4] )
          {
            case 'r':
            case 'R':
              type_r = REAL_PART_OF_COMPLEX;
              break;
            case 'j':
            case 'J':
              type_r = IMAGINARY_OF_COMPLEX;
              break;
            case 'e':
            case 'E':
              type_r = LONGHAND_REAL_NUMBER;
              break;
            default:
              break;
          }
        }
        /* ind */
        ei_ind( yy, nb );
        rndprc = rndsave;
        goto ind_exit;
      }
      /* inf ****************************************/
      else if( (s[1] == 'n' || s[1] == 'N') &&
               (s[2] == 'f' || s[2] == 'F')   )
      {
        if( s[3] == '_' )
        {
          switch( s[4] )
          {
            case 'r':
            case 'R':
              type_r = REAL_PART_OF_COMPLEX;
              break;
            case 'j':
            case 'J':
              type_r = IMAGINARY_OF_COMPLEX;
              break;
            case 'e':
            case 'E':
              type_r = LONGHAND_REAL_NUMBER;
              break;
            default:
              break;
          }
        }
        /* inf */
        goto infinite;
      }
      else
      /**********************************************/
        goto errors;

    case 'n':
    case 'N':
      /* NaN ****************************************/
      if( (s[1] == 'a' || s[1] == 'A') &&
          (s[2] == 'n' || s[2] == 'N') )
      {
        if( s[3] == '_' )
        {
          switch( s[4] )
          {
            case 'r':
            case 'R':
              type_r = REAL_PART_OF_COMPLEX;
              break;
            case 'j':
            case 'J':
              type_r = IMAGINARY_OF_COMPLEX;
              break;
            case 'e':
            case 'E':
              type_r = LONGHAND_REAL_NUMBER;
              break;
            default:
              break;
          }
        }
        /* nan */
        ei_nan( yy, (unsigned)nsign, nb );
        rndprc = rndsave;
        goto ind_exit;
      }
      else
      /**********************************************/
        goto errors;

    default:
errors:
      type_r = ASCII_TO_REAL_ERROR;
      ei_nan( yy, (unsigned)0, nb );
      goto aexit;

  } /* End of switch( *s ) */

donchar:
  ++s;
  goto nextcom;

  /*************************
    Exponent interpretation
   *************************/
exponent:

  max_dexp = _get_maxdecexp_ptr( nb ); /* size ne+1 always */
  min_dexp = _get_mindecexp_ptr( nb ); /* size ne+1 always */
  ei_cpye_unpack( dexp, min_dexp, ne+1, ne+1 );
  ei_nege( dexp, dexp, ne+1 ); /* dexp == -(MINDECEXP) */

  esign = 1;
  ++s;

  /* Check for + or - */
  if( *s == '-' )
  {
    esign = -1;
    ++s;
  }
  if( *s == '+' ) ++s;

  while( (*s >= '0') && (*s <= '9') )
  {
    /* exp *= 10; */
    ei_shln( exp, exp, (unsigned)1, ne+1 );
    ei_shln( inc, exp, (unsigned)2, ne+1 );
    ei_adde( exp, inc, exp, ne+1 );

    /* exp += *s++ - '0'; */
    j = *s++ - '0';
    ei_cvte_unpack( inc, (EMUSHORT *)&j, ne+1, 1 );
    ei_adde( exp, exp, inc, ne+1 );

    if( ei_cmpe( exp, dexp, ne+1 ) > 0 ) /* exp > -(MINDECEXP) */
    {
      if( esign < 0 ) goto zero;
      else            goto infinite;
    }

  } /* End of while( is_digit(*s) ) */


  if( esign < 0 ) ei_nege( exp, exp, ne+1 ); /* exp = -exp */

  if( ei_cmpe( exp, max_dexp, ne+1 ) > 0 ) /* exp > (MAXDECEXP) */
  {
infinite:
    ei_infin( yy, (unsigned)nsign, nb ); /* Infinity */
    goto aexit;
  }

  if( ei_cmpe( exp, min_dexp, ne+1 ) < 0 ) /* exp < (MINDECEXP) */
  {
zero:
    ei_signull( yy, (unsigned)nsign, nb ); /* signed NULL */
    goto aexit;
  }

daldone:

  ei_sube( nexp, exp, nexp, ne+1 );

  /* Pad trailing zeros to minimize power of 10, per IEEE spec. */
  while( (ei_cmp0e( nexp, ne+1 ) > 0) &&
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
       (yy[ne+1] == (EMUSHORT)0) ) /* hgw == 0 */
#else
       (yy[ns+1] == (EMUSHORT)0) ) /* hgw == 0 */
#endif
  {
    ei_copyzlgw( xt, yy, nb );
    ei_shup( xt, (unsigned)2, nb );
    ei_addm( xt, yy, xt, nb );
    ei_shup( xt, (unsigned)1, nb );
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
    if( xt[ne+1] != (EMUSHORT)0 ) break; /* hgw != 0 */
#else
    if( xt[ns+1] != (EMUSHORT)0 ) break; /* hgw != 0 */
#endif
    ei_dece( nexp, nexp, ne+1 ); /* nexp -= 1; */
    ei_copyzlgw( yy, xt, nb );

  } /* End of while( (nexp > 0) && (hgw == 0) ) */

  if( (jc = ei_normalize( yy, nb )) > (__mpu_int32_t)NSBITS(nb) )
  {
    ei_cleaz( yy, nb );
    type_r = rc; /* количество цифр после точки превышает размер мантиссы */
    goto aexit;
  }

  /* lexp = (EXONE - 1 + NSBITS(nb)) - jc */
  ei_dece( lexp, exone, ne+1 );
  j = NSBITS( nb );
  ei_cvte_unpack(  inc,  (EMUSHORT *)&j, ne+1, 1 );
  ei_cvte_unpack( dexp, (EMUSHORT *)&jc, ne+1, 1 );
  ei_adde( lexp, lexp,  inc, ne+1 );
  ei_sube( lexp, lexp, dexp, ne+1 );

  /*
    Здесь главное, чтобы параметр int rcontrol не был равен 0,
    для того чтобы функция ei_mdenorm() использовала, ранее
    установленное значение RNDPRC
   */
  ei_mdenorm( yy, lost, 0, lexp, NSBITS_DEFAULT, nb );


  /******************************************
    Convert GO ON
   ******************************************/

  /* dexp = MAXP */
  for( i = 0; i < ne+1; i++ ) dexp[i] = (EMUSHORT)0;
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  dexp[1]    = HIGHT_EXMAX_P;
#else
  dexp[ne-1] = HIGHT_EXMAX_P;
#endif

  n_ten = _get_nten( nb );

  p = _get_tens_ptr( nb ); /* *p = 10**MAXP */

  /* Copy Exponents */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  ei_cpye_unpack( lexp, &yy[1],    ne+1, ne );
#else
  ei_cpye_unpack( lexp, &yy[ns+2], ne+1, ne );
#endif

  if( ei_cmp0e( nexp, ne+1 ) == 0 ) /* nexp == 0 */
  {
    j = 0;
    goto expdone;

  } /* End if( nexp == 0 ) */

  esign = 1;
  if( ei_cmp0e( nexp, ne+1 )  < 0 ) /* nexp  < 0 */
  {
    ei_nege( nexp, nexp, ne+1 );
    esign = -1;
    if( ei_cmpe( nexp, dexp, ne+1 ) > 0 ) /* nexp > MAXP */
    {
      /* Punt. Can't handle this without 2 divides */
      ei_copy( tt, p, nb );
      /* Copy Exponents */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
      ei_cpye_unpack( inc, &tt[1],    ne+1, ne );
#else
      ei_cpye_unpack( inc, &tt[ns+2], ne+1, ne );
#endif
      ei_sube( lexp, lexp, inc, ne+1 );
      j = ei_divm( yy, yy, tt, nb );
      ei_adde( lexp, lexp, exone, ne+1 );
      ei_sube( nexp, nexp, dexp, ne+1 );
    }

  } /* End if( nexp < 0 ) */
 
  p = _get_tens_ptr( nb );
  p += np*n_ten;

  /* xt = 1.0E0 */
  _gen_one( xt, nb );

  for( i = 0; i < ne+1; i++ )  exp[i] = (EMUSHORT)0;
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  exp[ne] = (EMUSHORT)1; /* exp = 1 */
#else
  exp[0]  = (EMUSHORT)1; /* exp = 1 */
#endif

  do
  {
    ei_ande( inc, exp, nexp, ne+1 );
    if( ei_cmp0e( inc, ne+1 ) ) /* if( exp & nexp ) */
      ei_mul( xt, xt, p, nb );
    p -= np;
    ei_adde( exp, exp, exp, ne+1 );

  } while( ei_cmpe( exp, dexp, ne+1 ) <= 0 ); /* exp <= MAXP */

  ei_copy( tt, xt, nb );

  /* Copy Exponent of TT */
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  ei_cpye_unpack( inc, &tt[1],    ne+1, ne );
#else
  ei_cpye_unpack( inc, &tt[ns+2], ne+1, ne );
#endif
  if( esign < 0 )
  {
    ei_sube( lexp, lexp, inc, ne+1 );
    j = ei_divm( yy, yy, tt, nb );
    ei_adde( lexp, lexp, exone, ne+1 );
  }
  else
  {
    ei_adde( lexp, lexp, inc, ne+1 );
    j = ei_mulm( yy, yy, tt, nb );
    ei_sube( lexp, lexp, exone, ne+1 );
    ei_ince( lexp, lexp, ne+1 ); /* lexp -= EXONE -1; */
  }

expdone:

  /*
    Здесь главное, чтобы параметр int rcontrol не был равен 0,
    для того чтобы функция ei_mdenorm() использовала, ранее
    установленное значение RNDPRC
   */
  ei_mdenorm( yy, (int)j, 0, lexp, NSBITS_DEFAULT, nb );

aexit:

  rndprc = rndsave;
#if MPU_WORD_ORDER_BIG_ENDIAN == 1
  yy[0]       = nsign; /* copy Sign */
#else
  yy[ne+ns+2] = nsign; /* copy Sign */
#endif

ind_exit:
  ei_copy( ei, yy, nb );

  /* FREE lstr **************/
  free( lstr );
  /**************************/

  /* FREE nexp **************/
  /* FREE lexp **************/
  /* FREE dexp **************/
  /* FREE exp ***************/
  /* FREE exone *************/
  /* FREE inc ***************/
  __mpu_sbrk( -(int)(6*(ne+1)*SIZE_OF_EMUSHORT) );
  /**************************/

  /* FREE yy ****************/
  /* FREE xt ****************/
  /* FREE tt ****************/
  __mpu_sbrk( -(int)(3*np*SIZE_OF_EMUSHORT) );
  /**************************/

  rc = type_r;
  return( rc );

} /* End of ei_ascii_to_real() */


/***************************************************************
  Hide internal symbols:
 ***************************************************************/

__mpu_hidden_decl(ei_real_to_ascii);
__mpu_hidden_decl(ei_ascii_to_real);

/*
  End of hide internal symbols.
 ***************************************************************/