text: /* floatlogic.c: logic functions, based on floatnum. */
  /*
      Copyright (C) 2007, 2008 Wolf Lammen.
  
      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 of the License , 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 program; see the file COPYING.  If not, write to:
  
        The Free Software Foundation, Inc.
        59 Temple Place, Suite 330
        Boston, MA 02111-1307 USA.
  
  
      You may contact the author by:
         e-mail:  ookami1 <at> gmx <dot> de
         mail:  Wolf Lammen
                Oertzweg 45
                22307 Hamburg
                Germany
  
  *************************************************************************/
  
  #include "floatlogic.h"
  #include "floatconst.h"
  
  #define MAXIDX ((LOGICRANGE-1) / BITS_IN_UNSIGNED)
  #define SIGNBIT (LOGICRANGE - 1 - MAXIDX * BITS_IN_UNSIGNED)
  
  static void
  _zeroextend(
    t_longint* longint)
  {
    int idx;
  
    idx = longint->length - 1;
    for (; ++idx <= (int)MAXIDX;)
      longint->value[idx] = 0;
  }
  
  signed char
  _signof(
    t_longint* longint)
  {
    return (longint->value[MAXIDX] & (1 << SIGNBIT)) != 0? -1:1;
  }
  
  static char
  _signextend(
    t_longint* longint)
  {
    unsigned mask;
    signed char sign;
  
    sign = _signof(longint);
    mask = (unsigned)(~0) << SIGNBIT;
    if (sign < 0)
      longint->value[MAXIDX] |= mask;
    else
      longint->value[MAXIDX] &= ~mask;
    return sign;
  }
  
  static void
  _neg(
    t_longint* longint)
  {
    int idx = -1;
    const int maxidx = MAXIDX;
    while (++idx <= maxidx && longint->value[idx] == 0);
    if (idx <= maxidx)
      longint->value[idx] = - longint->value[idx];
    while (++idx <= maxidx)
      longint->value[idx] = ~longint->value[idx];
  }
  
  char
  _floatnum2logic(
    t_longint* longint,
    cfloatnum x)
  {
    floatstruct tmp;
    int digits;
  
    digits = float_getexponent(x)+1;
    if (float_iszero(x) || digits <= 0)
    {
      longint->length = 1;
      longint->value[0] = 0;
    }
    else
    {
      if (digits > MATHPRECISION)
        return 0;
  
      float_create(&tmp);
      /* floatnum2longint rounds, we have to truncate first */
      float_copy(&tmp, x, digits);
      if (float_getsign(x) < 0)
        float_add(&tmp, &tmp, &c1, EXACT);
      _floatnum2longint(longint, &tmp);
      float_free(&tmp);
      if (_bitlength(longint) > LOGICRANGE)
        return 0;
    }
    _zeroextend(longint);
    if (float_getsign(x) < 0)
      _not(longint);
    return 1;
  }
  
  void
  _logic2floatnum(
    floatnum f,
    t_longint* longint)
  {
    int idx;
    signed char sign;
  
    sign = _signextend(longint);
    if (sign < 0)
      _neg(longint);
    idx = MAXIDX;
    while (idx >= 0 && longint->value[idx] == 0)
      --idx;
    if (idx < 0)
      longint->length = 0;
    else
      longint->length = idx + 1;
    _longint2floatnum(f, longint);
    float_setsign(f, sign);
  }
  
  void
  _not(
    t_longint* longint)
  {
    int idx;
  
    for (idx = -1; ++idx <= (int)MAXIDX;)
      longint->value[idx] = ~(longint->value[idx]);
  }
  
  void
  _and(
    t_longint* x1,
    t_longint* x2)
  {
    int idx;
  
    for (idx = -1; ++idx <= (int)MAXIDX;)
      x1->value[idx] = x1->value[idx] & x2->value[idx];
  }
  
  void
  _or(
    t_longint* x1,
    t_longint* x2)
  {
    int idx;
  
    for (idx = -1; ++idx <= (int)MAXIDX;)
      x1->value[idx] = x1->value[idx] | x2->value[idx];
  }
  
  void
  _xor(
    t_longint* x1,
    t_longint* x2)
  {
    int idx;
  
    for (idx = -1; ++idx <= (int)MAXIDX;)
      x1->value[idx] = x1->value[idx] ^ x2->value[idx];
  }
  
  void
  _shr(
    t_longint* x,
    unsigned shift)
  {
    int idx;
    const unsigned sign = _signof(x) < 0? ~0 : 0;
    const int moves = shift/BITS_IN_UNSIGNED;
    const int maxidx = MAXIDX;
  
    if (moves > 0)
    {
      shift -= moves * BITS_IN_UNSIGNED;
      for (idx = moves-1; ++idx <= maxidx;)
        x->value[idx-moves] = x->value[idx];
      idx = MAXIDX - moves + 1;
      if (idx < 0)
        idx = 0;
      for (; idx <= maxidx; ++idx)
        x->value[idx] = sign;
    }
    if (shift > 0)
    {
      for (idx = -1; ++idx < maxidx;)
        x->value[idx] = _longshr(x->value[idx], x->value[idx+1], shift);
      x->value[MAXIDX] = _longshr(x->value[MAXIDX], sign, shift);
    }
  }
  
  void
  _shl(
    t_longint* x,
    unsigned shift)
  {
    int moves, idx;
  
    moves = shift/BITS_IN_UNSIGNED;
    if (moves > 0)
    {
      shift -= moves * BITS_IN_UNSIGNED;
      for (idx = MAXIDX; idx >= moves; --idx)
        x->value[idx] = x->value[idx-moves];
      if (moves > (int)MAXIDX)
        moves = MAXIDX+1;
      for (idx = -1; ++idx < moves;)
        x->value[idx] = 0;
    }
    if (shift > 0)
    {
      for (idx = MAXIDX; idx > 0; --idx)
        x->value[idx] = _longshl(x->value[idx-1], x->value[idx], shift);
      x->value[0] <<= shift;
    }
  }
  