Logo Search packages:      
Sourcecode: xabacus version File versions  Download package

AbacusT.c

/*
 * @(#)AbacusT.c
 *
 * Copyright 2009  David A. Bagley, bagleyd@tux.org
 *
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the author not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * 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.
 *
 * Used tables from How to Learn Lee's Abacus by Lee Kai-chen.
 */

#include "AbacusP.h"

#define CHAR_TO_DIGIT(c) ((c >= 'A') ? c - 'A' + 10 : c - '0')
#define DIGIT_TO_CHAR(d) ((d >= 10) ? (char) ('A' + d - 10) : (char) ('0' + d))
#define IS_DIGIT(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'J'))
#define EPSILON 0.0000001

/* ignores decimal point and multiply signs, etc, etc */
static void simpleParser(AbacusWidget w, char * buffer,
            char* aString, char* bString, char *op)
{
      unsigned int i;
      int numberCount = 0, decimalCount = 0;
      Boolean digit = False, decimal = False, negate = False;
      int decimalPosition = w->abacus.decimalPosition;
      
      if (w->abacus.decks[BOTTOM].piece != 0)
            decimalPosition--;
      if (w->abacus.decimalPosition >= w->abacus.shiftPercent &&
                  w->abacus.decks[BOTTOM].piecePercent != 0)
            decimalPosition--;
      aString[0] = '\0';
      bString[0] = '\0';
      *op = ' ';
      for (i = 0; i < strlen(buffer); i++) {
            if (buffer[i] == 'q' || buffer[i] == 'Q') {
                  *op = buffer[i];
                  return;
            }
            if ((buffer[i] == '+' || buffer[i] == '-') &&
                        (numberCount == 0 || *op != ' ') && !digit) {
                  if (buffer[i] == '-')
                        negate = !negate;
            } else if (buffer[i] == '+' || buffer[i] == '-' ||
                        buffer[i] == '*' || buffer[i] == '/' ||
                        buffer[i] == 'v' || buffer[i] == 'u') {
                  if (*op != ' ')
                        return;
                  *op = buffer[i];
                  numberCount++;
                  decimalCount = 0;
                  digit = False;
                  decimal = False;
                  negate = False;
            } else if (buffer[i] == '.' && !decimal) {
                  decimal = True;
                  if (numberCount == 0)
                        (void) sprintf(aString, "%s%c", aString, '.');
                  else
                        (void) sprintf(bString, "%s%c", bString, '.');
            } else if (IS_DIGIT(buffer[i])) {
                  if (!decimal || decimalCount < decimalPosition) {
                        if (numberCount == 0) {
                              if (!digit && negate)
                                    (void) sprintf(aString, "%s-", aString);
                              (void) sprintf(aString, "%s%c", aString, buffer[i]);
                        } else {
                              if (!digit && negate)
                                    (void) sprintf(bString, "%s-", bString);
                              (void) sprintf(bString, "%s%c", bString, buffer[i]);
                        }
                        negate = False;
                  }
                  if (decimal) {
                        decimalCount++;
                  }
                  digit = True;
            }
      }
}

/* More generic */
#if 1
/* Taken from addition tables in "How to Learn Lee's Abacus, */
/* made a little more generic, to handle other bases. */
static void digitAdd(int a, int b, int carryIn,
            int base, int topFactor, int bottomNumber,
            int* lower, int* upper, int* carryOut)
{
      int newB = b + carryIn;
      int fractBase;
      int modB, modAns, ans;
      int divA, modDivAns, divAns;

      if (bottomNumber > base / 2) /* topFactor may not be set, Russian */
            fractBase = base;
      else
            fractBase = topFactor;
      modB = newB % fractBase;
      ans = a + newB;
      modAns = ans % fractBase;
      divA = a / fractBase;
      modDivAns = (ans % base) / fractBase;
      divAns = ans / base;
      if (modAns - modB >= 0)
            *lower = modB;
      else
            *lower = modB - fractBase;
      *upper = modDivAns - divA;
      *carryOut = divAns;
#ifdef OLD_DEBUG
      (void) printf("add:\t%d\t%d\t%d\t|\t%d\t%d\t%d\n", a, b, carryIn,
            *lower, *upper, *carryOut);
#endif
}

/* Taken from subtraction tables in "How to Learn Lee's Abacus, */
/* made a little more generic, go handle other bases. */
static void digitSubtract(int a, int b, int carryIn,
            int base, int topFactor, int bottomNumber,
            int* lower, int* upper, int* carryOut)
{
      int newB = b - carryIn;
      int fractBase;
      int modA, modB, ans;
      int divA, modDivAns, divAns;

      if (bottomNumber > base / 2) /* topFactor may not be set, Russian */
            fractBase = base;
      else
            fractBase = topFactor;
      modA = a % fractBase;
      modB = newB % fractBase;
      ans = a - newB;
      divA = a / fractBase;
      modDivAns = ((ans + base) % base) / fractBase;
      divAns = (ans - base + 1) / base;
      if (modA - modB >= 0)
            *lower = -modB;
      else
            *lower = fractBase - modB;
      *upper = modDivAns - divA;
      *carryOut = divAns;
#ifdef OLD_DEBUG
      (void) printf("sub:\t%d\t%d\t%d\t|\t%d\t%d\t%d\n", a, b, carryIn,
            *lower, *upper, *carryOut);
#endif
}

#else
/* Taken from addition tables in "How to Learn Lee's Abacus */
/* less generic */
static void digitAdd(int a, int b, int carryIn,
            int base, int topFactor, int bottomNumber,
            int* lower, int* upper, int* carryOut)
{
      int newB = b + carryIn;
      int fractBase;

      if (bottomNumber > base / 2) /* topFactor may not be set */
            fractBase = base;
      else
            fractBase = topFactor;
      *lower = 0;
      *upper = 0;
      *carryOut = 0;
      if (newB < fractBase) {
            if (a < fractBase) {
                  if ((a + newB) < fractBase) { /* table 1 */
                        *lower = newB;
                  } else { /* table 2 */
                        *lower = newB - fractBase;
                        if (bottomNumber > base / 2)
                              *carryOut = 1;
                        else
                              *upper = 1;
                  }
            } else {
                  if ((a + newB) < base) { /* table 1 */
                        *lower = newB;
                  } else { /* table 3 */
                        *lower = newB - fractBase;
                        *upper = -1;
                        *carryOut = 1;
                  }
            }
      } else {
            if ((a + newB) < base) { /* table 1 */
                  *lower = newB - fractBase;
                  *upper = 1;
            } else if (a >= fractBase && a + newB < base + fractBase) { /* table 4 */
                  *lower = newB - fractBase;
                  *upper = -1;
                  *carryOut = 1;
            } else { /* table 3 */
                  *lower = newB - base;
                  *carryOut = 1;
            }
      }
#ifdef OLD_DEBUG
      (void) printf("add %d\t%d\t%d\t|\t%d\t%d\t%d\n", a, b, carryIn,
            *lower, *upper, *carryOut);
#endif
}

/* Taken from subtraction tables in "How to Learn Lee's Abacus */
/* less generic */
static void digitSubtract(int a, int b, int carryIn,
            int base, int topFactor, int bottomNumber,
            int* lower, int* upper, int* carryOut)
{
      int newB = b - carryIn;
      int fractBase; /* Kludge but may not be a bad fix here */
      if (bottomNumber > base / 2) /* topFactor may not be set */
            fractBase = base;
      else
            fractBase = topFactor;
      *lower = 0;
      *upper = 0;
      *carryOut = 0; /* if used is negative, i.e. a borrow */
      if (newB <= fractBase) {
            if (a < fractBase) {
                  if ((a - newB) >= 0) { /* table 1 */
                        *lower = -newB;
                  } else { /* table 3 */
                        *lower = fractBase - newB;
                        if (bottomNumber <= base / 2)
                              *upper = 1;
                        *carryOut = -1;
                  }
            } else {
                  if ((a - newB) >= fractBase) { /* table 2, 3 */
                        *lower = -newB;
                  } else { /* table 1 */
                        *lower = fractBase - newB;
                        *upper = -1;
                  }
            }
      } else {
            if ((a - newB) >= 0) { /* table 1 */
                  *lower = fractBase - newB;
                  *upper = -1;
            } else if (a < fractBase && (a - newB) >= -fractBase) { /* table 4 */
                  *lower = fractBase - newB;
                  *upper = 1;
                  *carryOut = -1;
            } else { /* table 3 */
                  *lower = base - newB;
                  *carryOut = -1;
            }
      }
#ifdef OLD_DEBUG
      (void) printf("sub %d\t%d\t%d\t|\t%d\t%d\t%d\n", a, b, carryIn,
            *lower, *upper, *carryOut);
#endif
}
#endif

/*
Guide:
2+1, 2+6, 2+4, 9+7, 36+75
10-3, 12-6, 100-58
67*2, 9*7, 26*14, 678*345
93/3, 1476/12, 638/22

Lee:
859*7, 54*23, 864*315, 26.5*3.4, .753*.04
4571/7, 7448/76, 72.61/2.74
625v, 1664.64v, 1004004v
12167u, 8615.125u, 8036.054027u
*/

#ifdef OLD_DEBUG
/* Unit Test */
static void testTable()
{
      int i, j, carryIn, k, lower, upper, carryOut;
#if 1
      int base = DEFAULT_BASE;
      int factor = 5;
#else
      int base = 16;
      int factor = 4;
#endif
      int c = 1;
      /*int c = 2;*/

      for (k = 0 ; k < c; k++) {
            for (j = 0 ; j < base; j++) {
                  for (i = 0 ; i < base; i++) {
                        carryIn = k;
#if 0
                        digitAdd(i, j, carryIn,
                              base, factor, factor,
                              &lower, &upper, &carryOut);
#else
                        digitSubtract(i, j, carryIn,
                              base, factor, factor,
                              &lower, &upper, &carryOut);
#endif
                        (void) printf("%d\t%d\t%d\t|\t%d\t%d\t%d\n",
                              i, j, carryIn, lower, upper, carryOut);
                  }
            }
      }
}
#endif

/* Feeback lines to user */
static void drawLineText(AbacusWidget w, char* line, int i)
{
#ifdef WINVER
#ifdef DEMO_FRAMED
      (void) SetTextColor(w->core.hDC, w->abacusDemo.foregroundGC);
      (void) SetBkMode(w->core.hDC, TRANSPARENT);
      (void) TextOut(w->core.hDC,
            1,
            w->core.height + w->abacusDemo.fontHeight * i - 1,
            line, (signed) strlen(line));
#else
      drawTeachText(line, i);
#endif
#else
      setAbacusText(w, ACTION_TEACH_LINE, line, i);
#endif
}

/* Position of decimal point in string */
static int getDecimalStringPosition(char * string)
{
      int i = 0;

      while (string[i] != '\0') {
            if (string[i] == '.')
                  return i;
            i++;
      }
      return i;
}

/* Position of decimal point in int array */
static int arrayLen(int * array)
{
      unsigned int i = 0;

      while (array[i] != -2) {
            i++;
      }
      return i;
}

/* Position of decimal point in int array */
static int getDecimalArrayPosition(int * array)
{
      unsigned int i = 0;

      while (array[i] != -2) {
            if (array[i] == -1)
                  return i;
            i++;
      }
      return i;
}

/* Appends decimal where necessary for consistency */
static void decimalSafe(char * aString, char * bString)
{
      int aDecimal = -1, bDecimal = -1;

      aDecimal = getDecimalStringPosition(aString);
      if (aDecimal == (int) strlen(aString)) {
            (void) sprintf(aString, "%s%c", aString, '.');
      }
      bDecimal = getDecimalStringPosition(bString);
      if (bDecimal == (int) strlen(bString)) {
            (void) sprintf(bString, "%s%c", bString, '.');
      }
}

/* Find decimal place offset given current position */
static int decimalPlaceString(char * string, int pos)
{
      int i = getDecimalStringPosition(string);

      if (i == (int) strlen(string) || i >= pos)
            return i - pos - 1;
      return i - pos;
}

/* Find decimal place offset given current position */
static int decimalPlaceArray(int * array, int pos)
{
      int i = getDecimalArrayPosition(array);

      if (i == arrayLen(array) || i >= pos)
            return i - pos - 1;
      return i - pos;
}

/* Find position offset given current place */
static int decimalOffsetString(char * string, int place)
{
      int i = getDecimalStringPosition(string);

      if (place < 0)
            return i - place;
      return i - place - 1;
}

#ifdef EXTRA
/* Find position offset given current place */
static int decimalOffsetArray(int * array, int place)
{
      int i = getDecimalArrayPosition(array);

      if (place < 0)
            return i - place;
      return i - place - 1;
}
#endif

/* Contract StringBuffer to remove leading and trailing 0's */
static void contractStringBuffer(char * string)
{
      int offset = getDecimalStringPosition(string);
      int i;

      for (i = 0; i < offset - 1; i++) {
            if (string[0] == '0')
                  (void) strcpy(string, &(string[1]));
            else
                  break;
      }
      if (offset < (int) strlen(string))
            for (i = (int) strlen(string) - 1; i > 1; i--) {
                  if (string[i] == '0')
                        string[i] = '\0';
                  else
                        break;
            }
      if (string[0] != '\0' && string[0] == '.') { /* normalize */
            for (i = (int) strlen(string); i >= 0; i--) {
                  string[i + 1] = string[i];
            }
            string[0] = '0';
      }
}

/* Expand StringBuffer to fit decimal place */
static void expandStringBuffer(char * string, int place)
{
      int offset = getDecimalStringPosition(string);
      int prependOffset = place - offset + 1;
      int appendOffset = offset + 1 - (int) strlen(string) - place;
      int i, len;

      len = (int) strlen(string);
      if (place > 0 && prependOffset > 0) {
            for (i = len; i >= 0; i--) {
                  string[i + prependOffset] = string[i];
            }
            for (i = 0; i < prependOffset; i++) {
                  string[i] = '0';
            }
      } else if (place < 0 && appendOffset > 0) {
            for (i = 0; i < appendOffset; i++) {
                  string[len + i] = '0';
            }
            string[len + appendOffset] = '\0';
      }
}

/* Shift StringBuffer to fit decimal place */
static void shiftStringBuffer(char * string, int shift)
{
      int offset = getDecimalStringPosition(string);
      int newOffset, i, j, k;

      j = strlen(string);
      if (offset != j)
            for (i = 0; i < j - offset; i++) {
                  string[offset + i]  = string[offset + i + 1];
            }
      j = strlen(string);
      if (offset >= j) {
            while (j > 1 && string[j - 1] == '0') {
                  string[j - 1] = string[j];
            }
      }
      if (offset == 1 && string[0] == '0') {
            while (strlen(string) > 1 &&
                        string[0] == '0') {
                  j = strlen(string);
                  for (i = 1; i <= j; i++) {
                        string[i - 1] = string[i];
                  }
                  offset--;
            }
      }
      if (string[0] == '0' && strlen(string) == 1) {
            return;
      }
      newOffset = offset + shift;
      if (newOffset <= 0) {
            for (i = 0; i < -newOffset; i++) {
                  j = strlen(string);
                  for (k = j; k >= 0; k--) {
                        string[k + 1] = string[k];
                  }
                  string[0] = '0';
            }
            j = strlen(string);
            for (i = j; i >= 0; i--) {
                  string[i + 2] = string[i];
            }
            string[0] = '0';
            string[1] = '.';
      } else if (newOffset >= (int) strlen(string)) {
            newOffset -= strlen(string);
            for (i = 0; i < newOffset; i++) {
                  j = strlen(string);
                  string[j] = '0';
                  string[j + 1] = '\0';
            }
      } else {
            for (i = strlen(string); i >= newOffset; i--) {
                  string[i + 1] = string[i];
            }
            string[newOffset] = '.';
      }
}

#ifdef OLD_DEBUG
void testShift(char * string)
{
      char my[512], yours[512];
      int i;

      (void) strcpy(my, string);
      for (i = -4; i < 5; i++) {
            (void) strcpy(yours, my);
            shiftStringBuffer(yours, i);
            (void) printf("my %s, i %d, yours %s\n",my, i, yours);
      }
}
#endif

/* Set string given change in rail (decimal position) */
static void setStringBuffer(AbacusWidget w, char * string, int aux,
            int place, int lower, int upper)
{
      int offset, digit;
      int topFactor, bottomNumber;
      AbacusWidget *wap = &w, wa;

      if (aux == 1 && w->abacus.leftAux != NULL)
            wap = (AbacusWidget *) w->abacus.leftAux;
      else if (aux == 2 && w->abacus.rightAux != NULL)
            wap = (AbacusWidget *) w->abacus.rightAux;
      wa = *wap;  
      topFactor = wa->abacus.decks[TOP].factor;
      bottomNumber = wa->abacus.decks[BOTTOM].number;
      if (bottomNumber <= wa->abacus.base / 2)
            digit = lower + upper * topFactor;
      else
            digit = lower;
      expandStringBuffer(string, place);
      offset = decimalOffsetString(string, place);
      string[offset] = DIGIT_TO_CHAR((digit + wa->abacus.base +
            CHAR_TO_DIGIT(string[offset])) % wa->abacus.base);
}

/* Appends 0's where necessary to adding is easier */
/* (before and after decimal point) */
static void addSafe(char * aString, char * bString)
{
      int aDecimal = -1, bDecimal = -1;
      int aCount, bCount, i;

      aDecimal = getDecimalStringPosition(aString);
      bDecimal = getDecimalStringPosition(bString);
      aCount = (int) strlen(aString) - aDecimal;
      bCount = (int) strlen(bString) - bDecimal;
      char temp[512];

      if (aCount > bCount) {
            for (i = bCount; i < aCount; i++)
                  (void) sprintf(bString, "%s%c", bString, '0');
      } else {
            for (i = aCount; i < bCount; i++)
                  (void) sprintf(aString, "%s%c", aString, '0');
      }
      if (aDecimal > bDecimal) {
            for (i = bDecimal; i < aDecimal; i++) {
                  (void) strcpy(temp, bString);
                  (void) sprintf(bString, "%c%s", '0', temp);
            }
      } else {
            for (i = aDecimal; i < bDecimal; i++) {
                  (void) strcpy(temp, aString);
                  (void) sprintf(aString, "%c%s", '0', temp);
            }
      }
}

/* Next rail according to step */
static int nextRail(AbacusWidget w, int step, int aux, Boolean rightToLeft,
            char * string)
{
      int n, rail;
      int count = (int) strlen(string) - 1;
      int decimalPosition = (int) strlen(string) - 1 -
            getDecimalStringPosition(string);
      int decimal = 0, shiftPercent;
      Boolean piece, piecePercent, subdeck;
      AbacusWidget *wap = &w, wa;

      if (aux == 1 && w->abacus.leftAux != NULL)
            wap = (AbacusWidget *) w->abacus.leftAux;
      else if (aux == 2 && w->abacus.rightAux != NULL)
            wap = (AbacusWidget *) w->abacus.rightAux;
      wa = *wap;  
      shiftPercent = wa->abacus.shiftPercent;
      piece = checkPiece(wa);
      piecePercent = checkPiecePercent(wa);
      subdeck = checkSubdeck(wa, 3);

      n = step;
      if (rightToLeft) {
            if (w->abacus.carryStep != 0)
                  n += (w->abacus.carryStep / 2);
            if (n >= decimalPosition -
                  ((piece) ? 1 : 0) -
                        ((piecePercent) ? 1 : 0) -
                        ((subdeck) ? 2 : 0)) {
                  decimal++;
            }
            n += decimal;
            rail = n - decimalPosition;
            if (subdeck) {
                  rail += 2;
            } else {
                  if (rail >= -1 + ((piecePercent) ? 1 : 0) &&
                              piece)
                        rail++;
                  if (rail >= -shiftPercent - 2 &&
                              piecePercent)
                        rail++;
                  if (n >= decimalPosition) {
                        rail--;
                  }
            }
      } else {
            if (w->abacus.carryStep != 0)
                  n += -(w->abacus.carryStep / 2);
            if (n >= count - decimalPosition +
                        ((piece) ? 1 : 0) +
                        ((piecePercent) ? 1 : 0) -
                        ((subdeck) ? 2 : 0)) {
                  decimal++;
            }
            rail = count - n - decimalPosition - 1;
            n += decimal;
            if (subdeck) {
                  rail += 3;
            } else {
                  if (piece && n <= count - decimalPosition +
                              ((piecePercent) ? 1 : 0))
                        rail++;
                  if (n <= count - decimalPosition +
                              shiftPercent + 2 &&
                              piecePercent)
                        rail++;
                  if (n <= count - decimalPosition +
                              shiftPercent + 2 &&
                              piecePercent)
                        rail++;
            }
      }
#ifdef OLD_DEBUG
      (void) printf("nextRail: %d\n", rail);
#endif
      return rail;
}

/* Next digit in string according to step */
static int nextCharPosition(AbacusWidget w, int step, int carryStep, int aux,
            Boolean rightToLeft, char * string)
{
      int n, a;
      int count = (int) strlen(string) - 1;
      int decimalPosition = (int) strlen(string) - 1 -
            getDecimalStringPosition(string);
      int decimal = 0, shiftPercent;
      Boolean piece, piecePercent, subdeck;
      AbacusWidget *wap = &w, wa;

      if (aux == 1 && w->abacus.leftAux != NULL)
            wap = (AbacusWidget *) w->abacus.leftAux;
      else if (aux == 2 && w->abacus.rightAux != NULL)
            wap = (AbacusWidget *) w->abacus.rightAux;
      wa = *wap;  
      shiftPercent = wa->abacus.shiftPercent;
      piece = checkPiece(wa);
      piecePercent = checkPiecePercent(wa);
      subdeck = checkSubdeck(wa, 3);

      n = step;
      if (rightToLeft) {
            if (carryStep != 0)
                  n += (carryStep / 2);
            if (n >= decimalPosition -
                        ((piece) ? 1 : 0) -
                        ((piecePercent) ? 1 : 0) -
                        ((subdeck) ? 2 : 0)) {
                  decimal++;
            }
            n += decimal;
            if (n > count)
                  a = -1;
            else
                  a = count - n;
      } else {
            if (carryStep != 0)
                  n += -(carryStep / 2);
            if (n >= count - decimalPosition +
                        ((piece) ? 1 : 0) +
                        ((piecePercent) ? 1 : 0) -
                        ((subdeck) ? 2 : 0)) {
                  decimal++;
            }
            n += decimal;
            if (n < 0)
                  a = -1;
            else
                  a = n;
      }
#ifdef OLD_DEBUG
      (void) printf("nextCharPosition: %d at step %d in %s\n", a, step, string);
#endif
      return a;
}

/* Digit at position in string */
static int nextChar(char * string, int pos)
{
      int digit;

      if (pos < 0 || pos >= (int) strlen(string)) {
            digit = 0;
      } else {
            digit = CHAR_TO_DIGIT(string[pos]);
      }
#ifdef OLD_DEBUG
      (void) printf("nextChar: %d at %d in %s\n", digit, pos, string);
#endif
      return digit;
}

/* Number of steps in addition and subtraction */
static int addSteps(char * string)
{
      /* decimal included */
      return (int) strlen(string) - 1;
}

/* Number of multiply steps in multiplication */
static int multSteps(char * aString, char * bString)
{
      /* decimal included */
      return ((int) strlen(aString) - 1) * ((int) strlen(bString) - 1);
}

/* Number of addition steps in multiplication */
static int addMultSteps(char * aString, char * bString)
{
      /* 2 digits per multiplication */
      return 2 * multSteps(aString, bString);
}

/* Finds out number of division steps */
/* This can be better as answers with 0s have to many ops */
static int divSteps(AbacusWidget w, char * aString, char * bString,
            int decimalPosition)
{
      double a, b, c, threshold = 1.0;
      int count = 0, i;

      if (strlen(aString) == 0 || strlen(bString) == 0)
            return 0;
      a = convertToDecimal(w->abacus.base, aString);
      b = convertToDecimal(w->abacus.base, bString);
      if (b == 0.0)
            return 0;
      c = a / b;
      for (i = 0; i < decimalPosition; i++)
            threshold /= w->abacus.base;
      if (c < threshold)
            return 0;
      if (c >= 1.0) {
            while (c >= 1.0) {
                  c /= w->abacus.base;
                  count++;
            }
      } else {
            while (c < 1.0) {
                  c *= w->abacus.base;
                  count--;
            }
            count++;
      }
      return count;
}

/* Number of multiplying steps in division */
static int multDivSteps(AbacusWidget w, char * aString, char * bString)
{
      /* decimal included */
      return divSteps(w, aString, bString, w->abacus.decimalPosition) *
            (strlen(bString) - 1);
}

/* Number of subtraction steps for each multiplication in division */
static int subMultDivSteps(AbacusWidget w, char * aString, char * bString)
{
      /* 2 digits per multiplication */
      return 2 * multDivSteps(w, aString, bString);
}

/* Finds head digits for division */
static double headDividend(AbacusWidget w, char * string, int len)
{
      char newString[512];

      if (strlen(string) == 0)
            return 0.0;
      (void) strcpy(newString, string);
      shiftStringBuffer(newString, -len);
      return convertToDecimal(w->abacus.base, newString);
}

/* Finds head digits for division */
/* Probably will not keep since could overflow if not BigDecimal */
static double headDivisor(AbacusWidget w, char * string)
{
      if (strlen(string) == 0)
            return 0.0;
      return convertToDecimal(w->abacus.base, string);
}

/* Divide string into groups, size of group depends on root */
static void rootGroup(AbacusWidget w, char* string, int root, int** group)
{
      int decimal = getDecimalStringPosition(string);
      int length = strlen(string);
      int nIntegral = decimal;
      int nDecimal = length - decimal - 1;
      int i, j, k, b, n;

      if (nIntegral == 1 && string[0] == '0')
            nIntegral = 0;
      nIntegral = (nIntegral + root - 1) / root;
      nDecimal = (nDecimal + root - 1) / root;
      n = nIntegral + nDecimal + 1;
      if (*group != NULL)
            free(*group);
      *group = (int *) malloc(sizeof (int) * n + 1);
      for (i = 0; i < nIntegral; i++) {
            k = i * root + (decimal + root - 1) % root;
            (*group)[i] = 0;
            b = 1;
            for (j = 0; j < root; j++) {
                  if (k - j >= 0)
                        (*group)[i] += b * CHAR_TO_DIGIT(string[k - j]);
                  else
                        break;
                  b *= w->abacus.base;
            }
      }
      (*group)[nIntegral] = -1;
      for (i = 0; i < nDecimal; i++) {
            k = i * root + 1 + decimal;
            (*group)[i + nIntegral + 1] = 0;
            b = 1;
            for (j = 0; j < root; j++) {
                  if (k + root - 1 - j < length)
                        (*group)[i + nIntegral + 1] += b *
                              CHAR_TO_DIGIT(string[k + root - 1 - j]);
                  b *= w->abacus.base;
            }
      }
      (*group)[n] = -2;
}

#ifdef DEBUG
/* Implement an iteration of Newton's Method or Halley's Method */
static double rootAdvance(double x, double p, int n)
{
      int i = 0;
      double y = x;

      if (n < 1)
            return 0;
      if (n == 1)
            return x;
      /* Halley's Method, converges faster */
      if (n == 2) {
            y = x * x;
#ifdef DEBUG
            (void) printf("p %g, y %g, n %d, x %g\n", p, y, n, x);
#endif
            return x * (y + p * 3) / (y * 3 + p);
      }
      if (n == 3) {
            y = x * x * x;
#ifdef DEBUG
            (void) printf("p %g, y %g, n %d, x %g\n", p, y, n, x);
#endif
            return x * (y + p * 2) / (y * 2 + p);
      }
      /* Newton's Method */
      for (i = 0; i < n - 2; i++)
            y *= x;
#ifdef DEBUG
      (void) printf("p %g, y %g, n %d, x %g\n", p, y, n, x);
#endif
      return (p / y + x * (n - 1)) / n;
}

/* Calculate root, loop a number of times and try for certain approximation */
static double rootApprox(double guess, double power, int n)
{
      int i;
      double xi = guess;
      const int iterations = 8;

      for (i = 0; i < iterations; i++) {
            double xn = rootAdvance(xi, power, n);
            double diff = xn - xi;

#ifdef DEBUG
            (void) printf("%d: %g %g %g\n", i, xn, xi, diff);
#endif
            if (diff < 0.0)
                  diff = -diff;  
            if (diff < EPSILON)
                  break;
            xi = xn;
      }
      return xi;
}

/* This calculates first digit in a root */
static void testRoot(AbacusWidget w, double guess, int position, int root)
{
      double c = convertToDecimal(w->abacus.base, w->abacus.cString);
      int aPlace = position;
      double start = guess;

      while (aPlace > 1) {
            start *= w->abacus.base;
            aPlace--;
      }
      while (aPlace < 0 && start != 0.0) {
            start = w->abacus.base / start;
            aPlace++;
      }
      c = rootApprox(guess, c, root);
#ifdef DEBUG
      (void) printf("incr root = %g\n", c);
#endif
      
}

/* Figure out next intGroup value */
static int intGroupValue(AbacusWidget w, int position) {
      int i, newPosition = position;

      if (position < 0)
            return 0;
      if (position >= arrayLen(w->abacus.intGroup))
            return 0;
      for (i = 0; i <= position; i++) {
            if (w->abacus.intGroup[i] == -1) { // only one decimal point
                  newPosition = position + 1;
                  break;
            }
      }
      if (newPosition >= arrayLen(w->abacus.intGroup))
            return 0;
      return w->abacus.intGroup[newPosition];
}

/* This will test Lee's method for calculating sqrt via Newton's Method */
static int testSqrtAdvance(AbacusWidget w, int power,
            int *digitSum, int *groupInc, int *groupSum)
{
      int digitAdd = 1;
      int i = 0;
      int digitSumOrig = *digitSum;
      int groupSumOrig = *groupSum;

      *groupInc += 1;
#ifdef DEBUG
      (void) printf("remainder power = %d\n", power);
#endif
      do {
            i++;
#ifdef DEBUG
            (void) printf("%d: %d %d\n", i, digitAdd, *groupInc);
#endif
            *digitSum += digitAdd;
            *groupSum += *groupInc;
            digitAdd = 2;
            *groupInc += digitAdd;
      } while (*groupSum + *groupInc <= power);
      *groupInc -= 2;
      if (i == 1) {
            (*groupInc)--;
            *digitSum = digitSumOrig;
            *groupSum = groupSumOrig;
      }
#ifdef DEBUG
      (void) printf("sum %d: %d %d : %d\n",
            i, *digitSum, *groupInc, *groupSum);
#endif
      return i;
}

/* This will test Lee's method for calculating sqrt via Newton's Method */
static void testSqrt(AbacusWidget w, int position)
{
      int i, power = 0, j;
      int digitSum = 0, groupInc = 0, groupSum = 0;
      int baseSq = w->abacus.base * w->abacus.base;
      int allDigitSum = 0, groupVal = 0;
      double sqrt = 0.0;
      int root = 2;

      for (i = 0; i <= position + w->abacus.decimalPosition; i++) {
            groupVal = intGroupValue(w, i);
            power = (power - groupSum) * baseSq  + groupVal;
            digitSum = 0;
            groupSum = 0;
#ifdef DEBUG
            (void) printf("%d: incr power = %d at position %d, intGroup %d\n",
                  i, power, position, groupVal);
#endif
            digitSum *= w->abacus.base;
            groupSum *= baseSq;
            j = testSqrtAdvance(w, power,
                  &digitSum, &groupInc, &groupSum);
            if (j == 1) {
                  digitSum = 0;
                  groupInc = groupInc * w->abacus.base;
            } else {
                  digitSum++;
                  groupInc = (groupInc + 1) * w->abacus.base;
            }
#ifdef DEBUG
            (void) printf("%d: digitSum = %d, groupSum = %d, power = %d, j = %d\n",
                  i, digitSum, groupSum, power, j);
#endif
            allDigitSum = allDigitSum * w->abacus.base + digitSum;
      }
      allDigitSum--;
      sqrt = (allDigitSum + root - 1) / root;
#ifdef DEBUG
      (void) printf("allDigitSum %d, sqrtm = %g\n",
            allDigitSum, sqrt);
#endif
      for (i = 0; i < w->abacus.decimalPosition; i++) {
            sqrt /= w->abacus.base;
      }
#ifdef DEBUG
      (void) printf("sqrt = %g\n", sqrt);
#endif
}

/* This will test Lee's method for calculating cbrt via Newton's Method */
static int testCbrtAdvance(AbacusWidget w, int power, int *digitSum,
            int *orderInc, int *orderSum, int *groupInc, int *groupSum)
{
      int digitAdd = 1;
      int i = 0;
      int digitSumOrig = *digitSum;
      int orderSumOrig = *orderSum;
      int groupSumOrig = *groupSum;
      int doubleOrder = 0;

      *orderInc += 1;
      *groupInc += 1;
#ifdef DEBUG
      (void) printf("remainder power = %d\n", power);
#endif
      do {
            i++;
#ifdef DEBUG
            (void) printf("%d: %d %d %d\n",
                  i, digitAdd, *orderInc, *groupInc);
#endif
            *digitSum += digitAdd;
            *orderSum += *orderInc;
            *groupSum += *groupInc;
            digitAdd = 1;
            *orderInc += digitAdd;
            doubleOrder = *orderInc;
            i++;
#ifdef DEBUG
            (void) printf("%d: %d %d\n",
                  i, digitAdd, *orderInc);
#endif
            *digitSum += digitAdd;
            *orderSum += *orderInc;
            digitAdd = 2;
            *orderInc += digitAdd;
            doubleOrder += *orderInc;
            *groupInc += doubleOrder;
      } while (*groupSum + *groupInc <= power);
      *groupInc -= doubleOrder;
      *orderInc -= 2;
      if (i == 2) {
            *orderInc -= 2;
            (*groupInc)--;
            *digitSum = digitSumOrig;
            *orderSum = orderSumOrig;
            *groupSum = groupSumOrig;
      }
#ifdef DEBUG
      (void) printf("sum %d: %d : %d %d : %d %d\n", i, *digitSum,
            *orderInc, *orderSum, *groupInc, *groupSum);
#endif
      return i;
}

/* This will test Lee's method for calculating cbrt via Newton's Method */
static void testCbrt(AbacusWidget w, int position)
{
      int i, power = 0, j;
      int digitSum = 0;
      int orderInc = 0, orderSum = 0, groupInc = 0, groupSum = 0;
      int baseCb = w->abacus.base * w->abacus.base * w->abacus.base;
      int magnitude = w->abacus.base;
      int allDigitSum = 0, groupVal = 0;
      double cbrt = 0.0;
      int root = 3;

      for (i = 0; i <= position + w->abacus.decimalPosition; i++) {
            groupVal = intGroupValue(w, i);
            power = (power - groupSum) * baseCb  + groupVal;
            digitSum = 0;
            groupSum = 0;
#ifdef DEBUG
            (void) printf("%d: incr power = %d at position %d, intGroup %d\n",
                  i, power, position, groupVal);
#endif
            digitSum *= w->abacus.base;
            orderSum *= w->abacus.base;
            groupSum *= baseCb;
            j = testCbrtAdvance(w, power, &digitSum,
                  &orderInc, &orderSum, &groupInc, &groupSum);
            if (j == 2) {
                  digitSum = 0;
                  orderInc = orderInc * w->abacus.base;
            } else {
                  digitSum++;
                  orderInc = (orderInc + 1) * w->abacus.base;
            }
            magnitude *= w->abacus.base;
            groupInc = orderSum * magnitude + orderInc;
#ifdef DEBUG
            (void) printf("%d: digitSum = %d, orderSum = %d, groupSum = %d, power = %d, j = %d\n",
                  i, digitSum, orderSum, groupSum, power, j);
#endif
            allDigitSum = allDigitSum * w->abacus.base + digitSum;
      }
      allDigitSum--;
      cbrt = (allDigitSum + root - 1) / root;
#ifdef DEBUG
      (void) printf("allDigitSum %d, cbrtm = %g\n",
            allDigitSum, cbrt);
#endif
      for (i = 0; i < w->abacus.decimalPosition; i++) {
            cbrt /= w->abacus.base;
      }
#ifdef DEBUG
      (void) printf("cbrt = %g\n", cbrt);
#endif
}
#endif

/* Tell about what is going to happen */
static Boolean pendingUpdate(AbacusWidget w, char * buffer,
      int line, int position, int bottomNumber)
{
      Boolean done;

      (void) sprintf(buffer, "For rail %d", position);
      if (w->abacus.lower == 0 && w->abacus.upper == 0 &&
                  w->abacus.carry[w->abacus.state] == 0) {
            (void) sprintf(buffer, "%s, do nothing", buffer);
            w->abacus.step++; /* or else two do nothings */
            done = True;
      } else {
            if (w->abacus.lower != 0) {
                  (void) sprintf(buffer, "%s, %s %d",
                        buffer,
                        ((w->abacus.lower < 0) ? "take off" : "put on"),
                        ABS(w->abacus.lower));
                  if (bottomNumber <= DEFAULT_BASE / 2)
                        (void) sprintf(buffer, "%s %s lower deck",
                              buffer,
                              ((w->abacus.lower < 0) ? "from" : "to"));
            }
            if (w->abacus.upper != 0) {
                    (void) sprintf(buffer, "%s, %s %d %s upper deck",
                        buffer,
                        ((w->abacus.upper < 0) ? "take off" : "put on"),
                        ABS(w->abacus.upper),
                        ((w->abacus.upper < 0) ? "from" : "to"));
                  }
            if (w->abacus.carry[w->abacus.state] != 0) {
                  (void) sprintf(buffer, "%s, %s %d (on next move)",
                        buffer,
                        ((w->abacus.carry[w->abacus.state] > 0) ? "carry" : "borrow"),
                        ABS(w->abacus.carry[w->abacus.state]));
            }
            done = False;
      }
      (void) sprintf(buffer, "%s.", buffer);
      drawLineText(w, buffer, line);
      return done;
}

/* Handle addition and subtraction one step at a time */
static Boolean nextPositionSum(AbacusWidget w, char op,
            int *rPosition, int *rDigit, int *bDigit)
{
      int n = (w->abacus.step - 2) / 2; /* 2 step display */
      int max = addSteps(w->abacus.aString);
      int topFactor = w->abacus.decks[TOP].factor;
      int bottomNumber = w->abacus.decks[BOTTOM].number;
      Boolean rightToLeft = w->abacus.rightToLeftAdd;
      int rPos, bPos, place;

      /* rString can expand with carries. */
      /* bString does not change, so bPos will be predictable. */
      bPos = nextCharPosition(w, n, w->abacus.carryStep, 0,
            rightToLeft, w->abacus.bString);
      place = decimalPlaceString(w->abacus.bString, bPos);
      rPos = decimalOffsetString(w->abacus.rString, place);
      *rDigit = nextChar(w->abacus.rString, rPos);
      if (w->abacus.carryStep == 0)
            *bDigit = nextChar(w->abacus.bString, bPos);
      else
            *bDigit = 1;
      if (!rightToLeft)
            w->abacus.carry[w->abacus.state] = 0;
      if (op == '+')
            digitAdd(*rDigit, *bDigit,
                  w->abacus.carry[w->abacus.state],
                  w->abacus.base, topFactor, bottomNumber,
                  &(w->abacus.lower), &(w->abacus.upper),
                  &(w->abacus.carry[w->abacus.state]));
      else
            digitSubtract(*rDigit, *bDigit,
                  w->abacus.carry[w->abacus.state],
                  w->abacus.base, topFactor, bottomNumber,
                  &(w->abacus.lower), &(w->abacus.upper),
                  &(w->abacus.carry[w->abacus.state]));
      *rPosition = nextRail(w, n, 0, rightToLeft, w->abacus.bString);
      return (n >= max - 1);
}

/* Handle multiplication one step at a time */
static Boolean nextPositionProduct(AbacusWidget w,
            int *rPosition, int *aDigit, int *bDigit, int *bValue)
{
      int n = (w->abacus.step - 2) / 2; /* 2 step display */
      int max = addMultSteps(w->abacus.aString, w->abacus.bString);
      int topFactor = w->abacus.decks[TOP].factor;
      int bottomNumber = w->abacus.decks[BOTTOM].number;
      int bCount = (int) strlen(w->abacus.bString) - 1;
      Boolean rightToLeft = w->abacus.rightToLeftAdd;
      int aOffset, bOffset, rOffset;
      int aPlace, bPlace, rPlace, rDigit;

      aOffset = nextCharPosition(w,
            (n / 2) / bCount, /* 2 digits result for each multiplication */
            0, /* not place for carry */
            1, /* aux 1 */
            True, /* "a" side always starts on right */
            w->abacus.aString);
      aPlace = decimalPlaceString(w->abacus.aString, aOffset);
      *aDigit = nextChar(w->abacus.aString, aOffset);
      bOffset = nextCharPosition(w,
            (n / 2) % bCount, /* 2 digits result for each multiplication */
            0, /* not place for carry */
            2, /* aux 2 */
            w->abacus.rightToLeftMult, /* this can vary */
            w->abacus.bString);
      bPlace = decimalPlaceString(w->abacus.bString, bOffset);
      *bDigit = nextChar(w->abacus.bString, bOffset);
      rPlace = ((n % 2 == 0 && !rightToLeft) ||
            (n % 2 == 1 && rightToLeft)) ? 1 : 0;
      if (w->abacus.carryStep != 0) {
            rPlace += w->abacus.carryStep / 2;
            *bDigit = 1;
      }
      rPlace += aPlace + bPlace;
      expandStringBuffer(w->abacus.rString, rPlace);
      rOffset = decimalOffsetString(w->abacus.rString, rPlace);
      rDigit = nextChar(w->abacus.rString, rOffset);
      if (w->abacus.carryStep == 0) {
            /* 2 digits * 2 step display */
            if (((n % 2 == 0) && rightToLeft) ||
                ((n % 2 == 1) && !rightToLeft)) {
                  *bValue = (*aDigit * *bDigit) % w->abacus.base;
            } else {
                  *bValue = (*aDigit * *bDigit) / w->abacus.base;
            }
      } else {
            *aDigit = 0;
            *bDigit = 0;
            *bValue = 1;
      }
      if (!rightToLeft)
            w->abacus.carry[w->abacus.state] = 0;
      digitAdd(rDigit, *bValue,
            w->abacus.carry[w->abacus.state],
            w->abacus.base, topFactor, bottomNumber,
            &(w->abacus.lower), &(w->abacus.upper),
            &(w->abacus.carry[w->abacus.state]));
      *rPosition = rPlace;
      if (w->abacus.carry[w->abacus.state] != 0 && n % 2 == 1 &&
                  rightToLeft)
            return True; /* Do not want to forget carry */
      return (n >= max - 1);
}

/* Handle division one step at a time */
static Boolean nextPositionDivision(AbacusWidget w,
            int *rPosition, int *aDigit, int *bDigit, int *bValue)
{
      int n = (w->abacus.step - 2) / 2; /* 2 step display */
      int max = subMultDivSteps(w, w->abacus.aString,
            w->abacus.bString);
      int topFactor = w->abacus.decks[TOP].factor;
      int bottomNumber = w->abacus.decks[BOTTOM].number;
      int bCount = strlen(w->abacus.bString) - 1;
      Boolean rightToLeft = w->abacus.rightToLeftAdd;
      int bOffset, rOffset;
      int aPlace, bPlace, rPlace, rDigit;
      double dividend;

      if (n / (2 * bCount) == w->abacus.regCount / 2) {
            w->abacus.reg = w->abacus.regCount;
      } else {
            w->abacus.reg = -1;
      }
      if (w->abacus.reg >= 0) {
            AbacusWidget *wap = &w, wa;

            if (w->abacus.rightAux != NULL)
                  wap = (AbacusWidget *) w->abacus.rightAux;
            wa = *wap;  
            if (w->abacus.reg > 1)
                  (void) strcpy(w->abacus.cString, w->abacus.rString);
            w->abacus.regCount++;
            aPlace = divSteps(w, w->abacus.cString, w->abacus.bString,
                  wa->abacus.decimalPosition) - 1;
#ifdef DEBUG
            {
                  int aOffset = decimalPlaceString(w->abacus.cString,
                        aPlace);
                  (void) printf("aPlace = %d, aOffset = %d\n",
                        aPlace, aOffset);
            }
#endif
            dividend = headDividend(w, w->abacus.cString, aPlace);
            w->abacus.divisor = headDivisor(w, w->abacus.bString);
#ifdef DEBUG
            (void) printf("dividend = %g, divisor = %g\n",
                  dividend, w->abacus.divisor);
#endif
            if (w->abacus.divisor == 0)
                  w->abacus.qDigit = 0;
            else {
                  w->abacus.qDigit = (int) (dividend / w->abacus.divisor +
                        EPSILON);
            }
#ifdef DEBUG
            (void) printf("cString = %s, qDigit = %d\n",
                  w->abacus.cString, w->abacus.qDigit);
#endif
            w->abacus.qPosition = aPlace;
            digitAdd(0, w->abacus.qDigit, w->abacus.carry[w->abacus.state],
                  wa->abacus.base, wa->abacus.decks[TOP].factor, wa->abacus.decks[BOTTOM].number,
                  &(w->abacus.lower), &(w->abacus.upper),
                  &(w->abacus.carry[w->abacus.state]));
            return (n >= 2 * max * 2 * w->abacus.decimalPosition - 1);
      }
      bOffset = nextCharPosition(w,
            (n / 2) % bCount, /* 2 digits result for each multiplication */
            0, /* not place for carry */
            1, /* aux 1 */
            w->abacus.rightToLeftMult, /* this can vary */
            w->abacus.bString);
      bPlace = decimalPlaceString(w->abacus.bString, bOffset);
      *bDigit = nextChar(w->abacus.bString, bOffset);
      rPlace = ((n % 2 == 0 && !rightToLeft) ||
            (n % 2 == 1 && rightToLeft)) ? 1 : 0;
      if (w->abacus.carryStep != 0) {
            rPlace += w->abacus.carryStep / 2;
            *bDigit = 1;
      }
      rPlace += w->abacus.qPosition + bPlace;
      expandStringBuffer(w->abacus.rString, rPlace);
      rOffset = decimalOffsetString(w->abacus.rString, rPlace);
      rDigit = nextChar(w->abacus.rString, rOffset);
#ifdef OLD_DEBUG
      (void) printf("bOffset %d, bPlace %d, bDigit %d\n",
            bOffset, bPlace, *bDigit);
#endif
      if (w->abacus.carryStep == 0) {
            /* 2 digits * 2 step display */
            if (((n % 2 == 0) && rightToLeft) ||
                ((n % 2 == 1) && !rightToLeft)) {
                  *bValue = (w->abacus.qDigit * *bDigit) % w->abacus.base;
            } else {
                  *bValue = (w->abacus.qDigit * *bDigit) / w->abacus.base;
            }
      } else {
            *aDigit = 0;
            *bDigit = 0;
            *bValue = 1;
      }
      if (!rightToLeft)
            w->abacus.carry[w->abacus.state] = 0;
      digitSubtract(rDigit, *bValue, w->abacus.carry[w->abacus.state],
            w->abacus.base, topFactor, bottomNumber,
            &(w->abacus.lower), &(w->abacus.upper),
            &(w->abacus.carry[w->abacus.state]));
      *rPosition = rPlace;
      return (n >= 2 * max + 2 * w->abacus.decimalPosition - 1);
}

/* Handle root one step at a time */
static Boolean nextPositionRoot(AbacusWidget w, int root,
            int *rPosition, int *aDigit, int *bDigit, int *bValue)
{
      int n = (w->abacus.step - 2) / 2; /* 2 step display */
      int max = subMultDivSteps(w, w->abacus.aString,
            w->abacus.bString);
      int aOffset, aPlace;
      int power;

      if (w->abacus.reg >= 0) {
            AbacusWidget *wap = &w, wa;

            if (w->abacus.leftAux != NULL)
                  wap = (AbacusWidget *) w->abacus.leftAux;
            wa = *wap;  
            if (w->abacus.reg > 1)
                  (void) strcpy(w->abacus.cString, w->abacus.rString);
            w->abacus.regCount++;
            aOffset = 0;
            if (w->abacus.intGroup[aOffset] == -1)
                  aOffset++;
            aPlace = decimalPlaceArray(w->abacus.intGroup, aOffset);
#ifdef DEBUG
            (void) printf("aPlace = %d, aOffset = %d\n", aPlace, aOffset);
#endif
            if (w->abacus.intGroup[aOffset] == -1)
                  power = 0;
            else
                  power = w->abacus.intGroup[aOffset];
            w->abacus.qDigit = rootInt(power, root);
#ifdef DEBUG
            (void) printf("power = %d\n", power);
            (void) printf("cString = %s, qDigit = %d\n",
                  w->abacus.cString, w->abacus.qDigit);
#endif
            w->abacus.qPosition = aPlace;
#ifdef DEBUG
            testRoot(w, w->abacus.qDigit, aPlace, root);
            if (root == 2)
                  testSqrt(w, aPlace);
            else if (root == 3)
                  testCbrt(w, aPlace);
#endif
            digitAdd(0, w->abacus.qDigit, w->abacus.carry[w->abacus.state],
                  wa->abacus.base, wa->abacus.decks[TOP].factor, wa->abacus.decks[BOTTOM].number,
                  &(w->abacus.lower), &(w->abacus.upper),
                  &(w->abacus.carry[w->abacus.state]));
            return (n >= 2 * max * 2 * w->abacus.decimalPosition - 1);
      }
      /* Only figures out first digit so far */
      /* May want to fix with (a+b)(a+b) = a^2+2ab+b^2 for 2 digits */
      /* and (a+b+c)(a+b+c) = a^2+2ab+b^2+2bc+c^2+2ac for 3 digits */
      /* see Advanced Abacus by Takashi Kojima */
      w->abacus.lower = 0;
      w->abacus.upper = 0;
      /* reserved for future */
      *rPosition = 0;
      *aDigit = 0;
      *bDigit = 0;
      *bValue = 0;
      return True;
}

/* A little tricky as this is reentrant */
void teachStep(AbacusWidget w, char * buffer, int aux)
{
      char buffer1[120] = "";
      char buffer2[120] = "";
      char buffer3[120] = "";
      int base = w->abacus.base;
      int bottomNumber = w->abacus.decks[BOTTOM].number;
      double a, b;

      if (w->abacus.step == 0) {
#ifdef OLD_DEBUG
            testTable();
#endif
            drawLineText(w, (char *) "Enter calculation X+Y, X-Y, X*Y, or X/Y where X positive and result positive.", 0);
            drawLineText(w, (char *) "Press enter to go through calculation steps.", 1);
            (void) sprintf(buffer3, "(addition order will be: %s; multiplicand order will be %s)",
                  ((w->abacus.rightToLeftAdd) ? "right to left" : "left to right"),
                  ((w->abacus.rightToLeftMult) ? "right to left" : "left to right"));
            drawLineText(w, buffer3, 2);
            w->abacus.reg = -1;
            w->abacus.regCount = 0;
            w->abacus.carryStep = 0;
            w->abacus.carry[0] = 0;
            w->abacus.carry[1] = 0;
#ifndef WINVER
            if (w->abacus.aString)
                  free(w->abacus.aString);
            if (w->abacus.bString)
                  free(w->abacus.bString);
            if (w->abacus.cString)
                  free(w->abacus.cString);
            if (w->abacus.rString)
                  free(w->abacus.rString);
            if (w->abacus.sString)
                  free(w->abacus.sString);
            if ((w->abacus.aString = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2)) &&
               (w->abacus.bString = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2)) &&
               (w->abacus.cString = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2)) &&
               (w->abacus.rString = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2)) &&
               (w->abacus.sString = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2)))
#endif
                  w->abacus.step++;
      } else if (w->abacus.step == 1) {
            simpleParser(w, buffer, w->abacus.aString, w->abacus.bString,
                  &(w->abacus.op));
#ifdef DEBUG
            (void) printf("buffer = %s %c %s\n",
                  w->abacus.aString, w->abacus.op, w->abacus.bString);
#endif
            if (w->abacus.op == 'q' || w->abacus.op == 'Q') {
                  return;
            }
            if (w->abacus.anomaly != 0) {
                  addBackAnomaly(w->abacus.aString, w->abacus.anomaly,
                        w->abacus.shiftAnomaly,
                        base);
            }
            if (w->abacus.anomalySq != 0) {
                  addBackAnomaly(w->abacus.aString, w->abacus.anomalySq,
                        w->abacus.shiftAnomaly + w->abacus.shiftAnomalySq,
                        base);
            }
            if (checkSubdeck(w, 3)) {
                  zeroFractionalPart(w->abacus.aString);
                  zeroFractionalPart(w->abacus.bString);
            }
            contractStringBuffer(w->abacus.aString);
            contractStringBuffer(w->abacus.bString);
#ifdef OLD_DEBUG
            testShift(w->abacus.aString);
#endif
            if (w->abacus.op == '+' || w->abacus.op == '-') {
                  convertStringToAbacus(w, w->abacus.aString, aux);
                  if (w->abacus.leftAux != NULL)
                        convertStringToAbacus(w, (char *) "0.0", 1);
                  if (w->abacus.rightAux != NULL)
                        convertStringToAbacus(w, (char *) "0.0", 2);
                  a = convertToDecimal(base, w->abacus.aString);
                  b = convertToDecimal(base, w->abacus.bString);
                  if (w->abacus.op == '-' && b > a) {
                        /* Revisit this, it should be allowed, but
                           rails probably need to be respected. */
                        (void) sprintf(buffer1,
                              "Subtraction underflow %s - %s",
                              w->abacus.aString, w->abacus.bString);
                        drawLineText(w, buffer1, 0);
                        w->abacus.step = 0;
                        return;
                  }
                  (void) sprintf(buffer1, "%sing %s %c %s",
                        ((w->abacus.op == '+') ? "Add" : "Subtract"),
                        w->abacus.aString, w->abacus.op,
                        w->abacus.bString);
                  drawLineText(w, buffer1, 0);
                  decimalSafe(w->abacus.aString, w->abacus.bString);
                  addSafe(w->abacus.aString, w->abacus.bString);
                  (void) strcpy(w->abacus.rString, w->abacus.aString);
                  (void) sprintf(buffer3, "Current answer: %s",
                        w->abacus.rString);
                  drawLineText(w, buffer3, 2);
                  w->abacus.step++;
            } else if (w->abacus.op == '*') {
                  if (strlen(w->abacus.aString) == 0)
                        return;
                  convertStringToAbacus(w, (char *) "0.0", 0);
                  if (w->abacus.leftAux != NULL)
                        convertStringToAbacus(w, w->abacus.aString, 1);
                  a = convertToDecimal(base, w->abacus.aString);
                  if (w->abacus.rightAux != NULL)
                        convertStringToAbacus(w, w->abacus.bString, 2);
                  b = convertToDecimal(base, w->abacus.bString);
                  if (a < 0.0 || b < 0.0) {
                        (void) sprintf(buffer1,
                              "Multiplication underflow %s * %s",
                              w->abacus.aString, w->abacus.bString);
                        drawLineText(w, buffer1, 0);
                        w->abacus.step = 0;
                        return;
                  }
                  (void) sprintf(buffer1, "Multiplying %s %c %s",
                        w->abacus.aString, w->abacus.op,
                        w->abacus.bString);
                  if (!w->abacus.lee) {
                        (void) sprintf(buffer1, "%s%s", buffer1,
                              " ... works best with lee option");
                  }
                  drawLineText(w, buffer1, 0);
                  decimalSafe(w->abacus.aString, w->abacus.bString);
                  (void) sprintf(w->abacus.rString, "0.");
                  (void) sprintf(buffer3, "Current answer: %s",
                        w->abacus.rString);
                  drawLineText(w, buffer3, 2);
                  w->abacus.step++;
            } else if (w->abacus.op == '/') {
                  if (strlen(w->abacus.aString) == 0)
                        return;
                  convertStringToAbacus(w, (char *) "0.0", 2);
                  convertStringToAbacus(w, w->abacus.aString, 0);
                  a = convertToDecimal(base, w->abacus.aString);
                  if (w->abacus.rightAux != NULL)
                        convertStringToAbacus(w, w->abacus.bString, 1);
                  b = convertToDecimal(base, w->abacus.bString);
                  if (a < 0.0 || b < 0.0) {
                        (void) sprintf(buffer1,
                              "Division underflow %s * %s",
                              w->abacus.aString, w->abacus.bString);
                        drawLineText(w, buffer1, 0);
                        w->abacus.step = 0;
                        return;
                  }
                  if (b == 0.0) {
                        (void) sprintf(buffer1, "Division overflow %s / %s",
                              w->abacus.aString, w->abacus.bString);
                        drawLineText(w, buffer1, 0);
                        w->abacus.step = 0;
                        return;
                  }
                  contractStringBuffer(w->abacus.aString);
                  (void) sprintf(buffer1, "Dividing %s %c %s",
                        w->abacus.aString, w->abacus.op,
                        w->abacus.bString);
                  if (!w->abacus.lee) {
                        (void) sprintf(buffer1, "%s%s", buffer1,
                              " ... works best with lee option");
                  }
                  drawLineText(w, buffer1, 0);
                  decimalSafe(w->abacus.aString, w->abacus.bString); /* quotient */
                  (void) strcpy(w->abacus.rString, w->abacus.aString);
                  (void) sprintf(w->abacus.sString, "0.");
                  (void) sprintf(buffer3, "Current answer: %s",
                        w->abacus.sString);
                  drawLineText(w, buffer3, 2);
                  w->abacus.step++;
                  w->abacus.reg = 0;
                  (void) strcpy (w->abacus.cString, w->abacus.aString); /* remainder */
            } else if (w->abacus.op == 'v' || w->abacus.op == 'u') {
                  rootGroup(w, w->abacus.aString,
                        (w->abacus.op == 'v') ? 2 : 3,
                        &(w->abacus.intGroup));
                  convertStringToAbacus(w, w->abacus.aString, aux);
                  if (w->abacus.leftAux != NULL)
                        convertStringToAbacus(w, (char *) "0.0", 1);
                  if (w->abacus.rightAux != NULL)
                        convertStringToAbacus(w, (char *) "0.0", 2);
                  a = convertToDecimal(base, w->abacus.aString);
                  (void) sprintf(buffer1, "%s root of %s",
                        ((w->abacus.op == 'v') ? "Square" : "Cube"),
                        w->abacus.aString);
                  if (!w->abacus.lee) {
                        (void) sprintf(buffer1, "%s%s", buffer1,
                              " ... works best with lee option");
                  }
                  drawLineText(w, buffer1, 0);
                  (void) strcpy(w->abacus.rString, w->abacus.aString);
                  (void) sprintf(w->abacus.sString, "0.");
                  (void) sprintf(buffer3, "Current answer: %s",
                        w->abacus.sString);
                  drawLineText(w, buffer3, 2);
                  w->abacus.step++;
                  w->abacus.reg = 0;
                  (void) strcpy (w->abacus.cString, w->abacus.aString); /* remainder */
            }
#ifdef DEBUG
            (void) printf("op buffer: %s %c %s %d %d\n",
                  w->abacus.aString, w->abacus.op,
                  w->abacus.bString, w->abacus.rightToLeftAdd,
                  w->abacus.rightToLeftMult);
#endif
            w->abacus.carry[0] = 0;
            w->abacus.carry[1] = 0;
      } else if (w->abacus.reg == 0 || (w->abacus.reg < 0 &&
                  ((w->abacus.carryStep != 0 && w->abacus.carryStep % 2 == 0 &&
                  w->abacus.carryStep >= 2) ||
                  (w->abacus.carryStep == 0 && w->abacus.step % 2 == 0 &&
                  w->abacus.step >= 2)))) {
            /* Tell user what is going to happen */
            int rPosition = 0;
            int aDigit = 0, bDigit = 0, bValue = 0;
            Boolean done = False;

            w->abacus.state = 0;
            if (w->abacus.op == '+' || w->abacus.op == '-') {
                  done = nextPositionSum(w, w->abacus.op,
                        &rPosition, &aDigit, &bDigit);
                  (void) sprintf(buffer1, "%sing %s %c %s",
                        ((w->abacus.op == '+') ? "Add" : "Subtract"),
                        w->abacus.aString, w->abacus.op,
                        w->abacus.bString);
                  if (w->abacus.carryStep == 0) {
                        char buf[120]; 

                        convertFromInteger(buf, base, aDigit);
                        (void) sprintf(buffer1,
                              "%s ... %s", buffer1, buf);
                        convertFromInteger(buf, base, bDigit);
                        (void) sprintf(buffer1,
                              "%s %c %s", buffer1, w->abacus.op, buf);
                        convertFromInteger(buf, base, aDigit + bDigit);
                        (void) sprintf(buffer1,
                              "%s = %s", buffer1, buf);
                        convertFromInteger(buf, base, bValue);
                  } else {
                        (void) sprintf(buffer1, "%s ... carrying %d",
                              buffer1, 1);
                  }
                  drawLineText(w, buffer1, 0);
            } else if (w->abacus.op == '*') {
                  done = nextPositionProduct(w,
                        &rPosition, &aDigit, &bDigit, &bValue);
                  (void) sprintf(buffer1, "Multiplying %s %c %s",
                        w->abacus.aString, w->abacus.op,
                        w->abacus.bString);
                  if (w->abacus.carryStep == 0) {
                        char buf[120]; 

                        convertFromInteger(buf, base, aDigit);
                        (void) sprintf(buffer1,
                              "%s ... %s", buffer1, buf);
                        convertFromInteger(buf, base, bDigit);
                        (void) sprintf(buffer1,
                              "%s * %s", buffer1, buf);
                        convertFromInteger(buf, base, aDigit * bDigit);
                        (void) sprintf(buffer1,
                              "%s = %s", buffer1, buf);
                        convertFromInteger(buf, base, bValue);
                        (void) sprintf(buffer1,
                              "%s, adding %s digit", buffer1, buf);
                  } else {
                        (void) sprintf(buffer1, "%s ... carrying %d",
                              buffer1, 1);
                  }
                  drawLineText(w, buffer1, 0);
            } else if (w->abacus.op == '/') {
                  done = nextPositionDivision(w,
                        &rPosition, &aDigit, &bDigit, &bValue);
                  contractStringBuffer(w->abacus.cString);
                  (void) sprintf(buffer1, "Dividing %s %c %s",
                        w->abacus.cString, w->abacus.op,
                        w->abacus.bString);
                  if (w->abacus.carryStep == 0 && w->abacus.divisor != 0) {
                        char buf[120];

                        convertFromInteger(buf, base, w->abacus.qDigit);
                        (void) sprintf(buffer1,
                              "%s ... %s", buffer1, buf);
                        convertFromDouble(buf, base, w->abacus.divisor);
                        (void) sprintf(buffer1,
                              "%s * %s", buffer1, buf);
                        convertFromDouble(buf, base,
                              w->abacus.divisor * w->abacus.qDigit);
                        (void) sprintf(buffer1,
                              "%s = %s", buffer1, buf);
                        if (w->abacus.reg >= 0) {
                              AbacusWidget *wap = &w, wa;
                              int bn;

                              if (w->abacus.rightAux != NULL)
                                    wap = (AbacusWidget *) w->abacus.rightAux;
                              wa = *wap;  
                              bn = wa->abacus.decks[BOTTOM].number;
                              convertFromInteger(buf, base,
                                    w->abacus.qDigit);
                              (void) sprintf(buffer1,
                                    "%s, register %s on second auxiliary, rail %d",
                                    buffer1, buf, w->abacus.qPosition);
                              drawLineText(w, buffer1, 0);
                              w->abacus.reg++;
                              (void) pendingUpdate(w, buffer2, 1,
                                    w->abacus.qPosition, bn);
                              return;
                        }
                        if (w->abacus.divisor != bDigit) {
                              convertFromInteger(buf, base, w->abacus.qDigit);
                              (void) sprintf(buffer1,
                                    "%s ... %s", buffer1, buf);
                              convertFromInteger(buf, base, bDigit);
                              (void) sprintf(buffer1,
                                    "%s * %s", buffer1, buf);
                              convertFromInteger(buf, base,
                                    w->abacus.qDigit * bDigit);
                              (void) sprintf(buffer1,
                                    "%s = %s", buffer1, buf);
                        }
                        convertFromInteger(buf, base, bValue);
                        (void) sprintf(buffer1,
                              "%s, subtracting %s digit", buffer1, buf);
                        drawLineText(w, buffer1, 0);
                  } else {
                        (void) sprintf(buffer1, "%s ... borrowing %d",
                              buffer1, 1);
                  }
                  drawLineText(w, buffer1, 0);
            } else if (w->abacus.op == 'v' || w->abacus.op == 'u') {
                  done = nextPositionRoot(w,
                        (w->abacus.op == 'v') ? 2 : 3,
                        &rPosition, &aDigit, &bDigit, &bValue);
                  (void) sprintf(buffer1, "Taking %s Root of %s",
                        (w->abacus.op == 'v') ? "Square" : "Cube", w->abacus.cString);
                  if (w->abacus.carryStep == 0) {
                        (void) sprintf(buffer1, "%s ... %d",
                              buffer1, w->abacus.qDigit);
                        if (w->abacus.op == 'u')
                              (void) sprintf(buffer1, "%s * %d",
                                    buffer1, w->abacus.qDigit);
                        (void) sprintf(buffer1, "%s * %d = %d",
                              buffer1, w->abacus.qDigit,
                              (w->abacus.qDigit * w->abacus.qDigit *
                              ((w->abacus.op == 'v') ? 1 : w->abacus.qDigit)));
                        if (w->abacus.reg >= 0) {
                              AbacusWidget *wap = &w, wa;
                              int bn;

                              if (w->abacus.leftAux != NULL)
                                    wap = (AbacusWidget *) w->abacus.leftAux;
                              wa = *wap;  
                              bn = wa->abacus.decks[BOTTOM].number;
                              (void) sprintf(buffer1,
                                    "%s, register %d on first auxiliary, rail %d",
                                    buffer1, w->abacus.qDigit, w->abacus.qPosition);
                              drawLineText(w, buffer1, 0);
                              w->abacus.reg++;
                              (void) pendingUpdate(w, buffer2, 1,
                                    w->abacus.qPosition, bn);
                              return;
                        }
                        (void) sprintf(buffer1, "%s ... subtracting %d digit",
                              buffer1, bValue);
                        drawLineText(w, buffer1, 0);
                  } else {
                        (void) sprintf(buffer1, "%s ... borrowing %d",
                              buffer1, 1);
                  }
                  drawLineText(w, buffer1, 0);
            }
            if (!pendingUpdate(w, buffer2, 1, rPosition, bottomNumber))
                  done = False;
            if (w->abacus.carry[w->abacus.state] == 0 &&
                        w->abacus.carryStep == 0 && done) {
                  contractStringBuffer(w->abacus.rString);
                  if (w->abacus.op == '/' ||
                              w->abacus.op == 'v' || w->abacus.op == 'u') {
                        contractStringBuffer(w->abacus.sString);
                        (void) sprintf(buffer3, "Final answer: %s",
                              w->abacus.sString);
                  } else {
                        (void) sprintf(buffer3, "Final answer: %s",
                              w->abacus.rString);
                  }
                  drawLineText(w, buffer3, 2);
                  w->abacus.step = 0;
            } else if (w->abacus.carryStep == 0) {
                  w->abacus.step++;
            } else {
                  w->abacus.carryStep++;
            }
      } else {
            /* Actually carry out what was told would happen */
            int rPosition = 0;
            int aDigit = 0, bDigit = 0, bValue = 0;
            Boolean done = False;

            if (!w->abacus.rightToLeftAdd)
                  w->abacus.carry[1] = w->abacus.carry[0];
            w->abacus.state = 1;
            if (w->abacus.op == '+' || w->abacus.op == '-') {
                  done = nextPositionSum(w, w->abacus.op,
                        &rPosition, &aDigit, &bDigit);
                  setStringBuffer(w, w->abacus.rString, 0,
                        rPosition, w->abacus.lower, w->abacus.upper);
            } else if (w->abacus.op == '*') {
                  done = nextPositionProduct(w,
                        &rPosition, &aDigit, &bDigit, &bValue);
                  setStringBuffer(w, w->abacus.rString, 0,
                        rPosition, w->abacus.lower, w->abacus.upper);
            } else if (w->abacus.op == '/') {
                  done = nextPositionDivision(w,
                        &rPosition, &aDigit, &bDigit, &bValue);
                  if (w->abacus.reg > 0) {
                        if (w->abacus.rightAux != NULL) {
                              if (w->abacus.lower != 0)
                                    setAbacusMove(w, ACTION_MOVE, 2, 0, w->abacus.qPosition,
                                          w->abacus.lower);
                              if (w->abacus.upper != 0)
                                    setAbacusMove(w, ACTION_MOVE, 2, 1, w->abacus.qPosition,
                                          w->abacus.upper);
                        }
                        setStringBuffer(w, w->abacus.sString, 2,
                              w->abacus.qPosition,
                              w->abacus.lower, w->abacus.upper);
                        w->abacus.reg = -1;
                        contractStringBuffer(w->abacus.sString);
                        (void) sprintf(buffer3, "Current answer: %s",
                              w->abacus.sString);
                        drawLineText(w, buffer3, 2);
                        return;
                  }
                  setStringBuffer(w, w->abacus.rString, 0,
                        rPosition, w->abacus.lower, w->abacus.upper);
                  a = convertToDecimal(base, w->abacus.rString);
                  if (a == 0.0) {
                        done = True;
                  }
            } else if (w->abacus.op == 'v' || w->abacus.op == 'u') {
                  done = nextPositionRoot(w,
                        (w->abacus.op == 'v') ? 2 : 3,
                        &rPosition, &aDigit, &bDigit, &bValue);
                  if (w->abacus.reg > 0) {
                        if (w->abacus.leftAux != NULL) {
                              if (w->abacus.lower != 0)
                                    setAbacusMove(w, ACTION_MOVE, 1, 0, w->abacus.qPosition,
                                          w->abacus.lower);
                              if (w->abacus.upper != 0)
                                    setAbacusMove(w, ACTION_MOVE, 1, 1, w->abacus.qPosition,
                                          w->abacus.upper);
                        }
                        setStringBuffer(w, w->abacus.sString, 1,
                              w->abacus.qPosition,
                              w->abacus.lower, w->abacus.upper);
                        w->abacus.reg = -1;
                        contractStringBuffer(w->abacus.sString);
                        (void) sprintf(buffer3, "Current answer: %s",
                              w->abacus.sString);
                        drawLineText(w, buffer3, 2);
                        return;
                  }
                  setStringBuffer(w, w->abacus.rString, 0,
                        rPosition, w->abacus.lower, w->abacus.upper);
                  a = convertToDecimal(base, w->abacus.rString);
                  if (a == 0.0) {
                        done = True;
                  }
            }
            if (w->abacus.lower != 0)
                  setAbacusMove(w, ACTION_MOVE, 0, 0, rPosition,
                        w->abacus.lower);
            if (w->abacus.upper != 0)
                  setAbacusMove(w, ACTION_MOVE, 0, 1, rPosition,
                        w->abacus.upper);
#if 0
            if (w->abacus.carry[w->abacus.state] != 0) {
                  setAbacusMove(w, ACTION_MOVE, 0, 0, rPosition + 1,
                        w->abacus.carry[w->abacus.state]);
                  w->abacus.carry[w->abacus.state] = 0;
            }
#endif
            if (w->abacus.carry[w->abacus.state] == 0 &&
                        w->abacus.carryStep != 0) {
                  w->abacus.carryStep = 0;
            }
            contractStringBuffer(w->abacus.rString);
            if (w->abacus.carry[w->abacus.state] == 0 &&
                        w->abacus.carryStep == 0 &&
                        done) {
                  w->abacus.step = 0;
                  if (w->abacus.op == '/' ||
                              w->abacus.op == 'v' || w->abacus.op == 'u') {
                        contractStringBuffer(w->abacus.sString);
                        (void) sprintf(buffer3, "Final answer: %s",
                              w->abacus.sString);
                  } else {
                        (void) sprintf(buffer3, "Final answer: %s",
                              w->abacus.rString);
                  }
                  drawLineText(w, buffer3, 2);
            } else {
                  if (w->abacus.op == '/' ||
                              w->abacus.op == 'v' || w->abacus.op == 'u') {
                        contractStringBuffer(w->abacus.sString);
                        (void) sprintf(buffer3, "Current answer: %s",
                              w->abacus.sString);
                  } else {
                        (void) sprintf(buffer3, "Current answer: %s",
                              w->abacus.rString);
                  }
                  drawLineText(w, buffer3, 2);
                  if ((done && w->abacus.rightToLeftAdd) ||
                              !w->abacus.rightToLeftAdd) {
                        if (w->abacus.carry[w->abacus.state] != 0) {
                              if (w->abacus.carryStep == 0) {
                                    w->abacus.carryStep = 2;
                                    if (w->abacus.rightToLeftAdd)
                                          w->abacus.carry[1] = w->abacus.carry[0] = 0;
                              } else {
                                    w->abacus.carryStep++;
                              }
                        }
                        if (w->abacus.carryStep == 0)
                              w->abacus.step++;
                  } else if (w->abacus.rightToLeftAdd) {
                        w->abacus.step++;
                  }
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index