File:  [Research Unix] / researchv10dc / cmd / icon / src / iconx / oarith.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 3 months ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Dan Cross

/*
 * File: oarith.c
 *  Contents: div, minus, mod, mult, neg, number, plus, power
 */

#include "../h/rt.h"
#ifdef SUN
#include <math.h>
#include <signal.h>
#endif SUN

#ifdef NoOver
#define Add(x,y) (x + y)
#define Sub(x,y) (x - y)
#define Mpy(x,y) (x * y)
#else NoOver
#define Add(x,y) ckadd(x,y)
#define Sub(x,y) cksub(x,y)
#define Mpy(x,y) ckmul(x,y)
#endif NoOver

/*
 * x / y - divide y into x.
 */

OpDcl(div,2,"/")
   {
   register int t1, t2;
   union numeric n1, n2;

   /*
    * x and y must be numbers.
    */
   if ((t1 = cvnum(&Arg1, &n1)) == NULL)
      runerr(102, &Arg1);
   if ((t2 = cvnum(&Arg2, &n2)) == NULL)
      runerr(102, &Arg2);

   if (!(t1 == T_Real || t2 == T_Real)) {
      /*
       * x and y are both integers, just divide them and return the result.
       */
      if (n2.integer == 0L)
         runerr(201, &Arg2);
      Mkint(n1.integer / n2.integer, &Arg0);
      }
   else {
      /*
       * Either x or y or both is real, convert the real values to integers,
       *  divide them, and return the result.
       */
      if (!(t1 == T_Real))
         n1.real = n1.integer;
      if (!(t2 == T_Real))
         n2.real = n2.integer;
#ifdef ZeroDivide
      if (n2.real == 0.0)
         runerr(204,0);
#endif ZeroDivide
      mkreal(n1.real / n2.real, &Arg0);
#ifdef SUN
      if (((struct b_real *)BlkLoc(Arg0))->realval == HUGE)
         kill(getpid(),SIGFPE);
#endif SUN
      }
   Return;
   }


/*
 * x - y - subtract y from x.
 */

OpDcl(minus,2,"-")
   {
   register int t1, t2;
   union numeric n1, n2;
#ifndef NoOver
   extern long cksub();
#endif NoOver

   /*
    * x and y must be numeric.  Save the cvnum return values for later use.
    */
   if ((t1 = cvnum(&Arg1, &n1)) == NULL)
      runerr(102, &Arg1);
   if ((t2 = cvnum(&Arg2, &n2)) == NULL)
      runerr(102, &Arg2);

   if (!(t1 == T_Real || t2 == T_Real)) {
      /*
       * Both x and y are integers.  Perform integer subtraction and place
       *  the result in Arg0 as the return value.
       */
      Mkint(Sub(n1.integer, n2.integer), &Arg0);
      }
   else {
      /*
       * Either x or y is real, convert the other to a real, perform
       *  the subtraction and place the result in Arg0 as the return value.
       */
      if (!(t1 == T_Real))
         n1.real = n1.integer;
      if (!(t2 == T_Real))
         n2.real = n2.integer;
      mkreal(n1.real - n2.real, &Arg0);
      }
   Return;
   }


/*
 * x % y - take remainder of x / y.
 */

OpDcl(mod,2,"%")
   {
   register int t1, t2;
   union numeric n1, n2;

   /*
    * x and y must be numeric.  Save the cvnum return values for later use.
    */
   if ((t1 = cvnum(&Arg1, &n1)) == NULL)
      runerr(102, &Arg1);
   if ((t2 = cvnum(&Arg2, &n2)) == NULL)
      runerr(102, &Arg2);

   if (!(t1 == T_Real || t2 == T_Real)) {
      /*
       * Both x and y are integers.  If y is 0, generate an error because
       *  it's divide by 0.  Otherwise, just return the modulus of the
       *  two arguments.
       */
      if (n2.integer == 0L)
         runerr(202, &Arg2);
      Mkint(n1.integer % n2.integer, &Arg0);
      }
   else {
      /*
       * Either x or y is real, convert the other to a real, perform
       *  the modulation, convert the result to an integer and place it
       *  in Arg0 as the return value.
       */
      if (!(t1 == T_Real))
         n1.real = n1.integer;
      if (!(t2 == T_Real))
         n2.real = n2.integer;
      mkreal(n1.real - n2.real * (int)(n1.real / n2.real), &Arg0);
      }
   Return;
   }


/*
 * x * y - multiply x and y.
 */

OpDcl(mult,2,"*")
   {
   register int t1, t2;
   union numeric n1, n2;
#ifndef NoOver
   extern long ckmul();
#endif NoOver

   /*
    * x and y must be numeric.  Save the cvnum return values for later use.
    */
   if ((t1 = cvnum(&Arg1, &n1)) == NULL)
      runerr(102, &Arg1);
   if ((t2 = cvnum(&Arg2, &n2)) == NULL)
      runerr(102, &Arg2);

   if (!(t1 == T_Real || t2 == T_Real)) {
      /*
       * Both x and y are integers.  Perform the multiplication and
       *  and place the result in Arg0 as the return value.
       */
      Mkint(Mpy(n1.integer,n2.integer), &Arg0);
      }
   else {
      /*
       * Either x or y is real, convert the other to a real, perform
       *  the subtraction and place the result in Arg0 as the return value.
       */
      if (!(t1 == T_Real))
         n1.real = n1.integer;
      if (!(t2 == T_Real))
         n2.real = n2.integer;
      mkreal(n1.real * n2.real, &Arg0);
      }
   Return;
   }


/*
 * -x - negate x.
 */

OpDcl(neg,1,"-")
   {
   union numeric n;
   long l;

   /*
    * x must be numeric.
    */
   switch (cvnum(&Arg1, &n)) {

      case T_Integer:
      case T_Longint:
         /*
          * If it's an integer, check for overflow by negating it and
          *  seeing if the negation didn't "work".  Use Mkint to
          *  construct the return value.
          */
         l = -n.integer;
         if (n.integer < 0 && l < 0)
            runerr(203, &Arg1);
         Mkint(l, &Arg0);
         break;

      case T_Real:
         /*
          * x is real, just negate it and use mkreal to construct the
          *  return value.
          */
         mkreal(-n.real, &Arg0);
         break;

      default:
         /*
          * x isn't numeric.
          */
         runerr(102, &Arg1);
      }
   Return;
   }


/*
 * +x - convert x to numeric type.
 *  Operational definition: generate runerr if x is not numeric.
 */

OpDcl(number,1,"+")
   {
   union numeric n;

   switch (cvnum(&Arg1, &n)) {

      case T_Integer:
      case T_Longint:
         Mkint(n.integer, &Arg0);
         break;

      case T_Real:
         mkreal(n.real, &Arg0);
         break;

      default:
         runerr(102, &Arg1);
      }
   Return;
   }


/*
 * x + y - add x and y.
 */

OpDcl(plus,2,"+")
   {
   register int t1, t2;
   union numeric n1, n2;
#ifndef NoOver
   extern long ckadd();
#endif NoOver

   /*
    * x and y must be numeric.  Save the cvnum return values for later use.
    */
   if ((t1 = cvnum(&Arg1, &n1)) == NULL)
      runerr(102, &Arg1);
   if ((t2 = cvnum(&Arg2, &n2)) == NULL)
      runerr(102, &Arg2);

   if (!(t1 == T_Real || t2 == T_Real)) {
      /*
       * Both x and y are integers.  Perform integer addition and plcae the
       *  result in Arg0 as the return value.
       */
      Mkint(Add(n1.integer, n2.integer), &Arg0);
      }
   else {
      /*
       * Either x or y is real, convert the other to a real, perform
       *  the addition and place the result in Arg0 as the return value.
       */
      if (!(t1 == T_Real))
         n1.real = n1.integer;
      if (!(t2 == T_Real))
         n2.real = n2.integer;
      mkreal(n1.real + n2.real, &Arg0);
      }
   Return;
   }




/*
 * x ^ y - raise x to the y power.
 */

OpDcl(power,2,"^")
   {
   register int t1, t2;
   union numeric n1, n2;
   extern double pow();
   extern long ipow();

   /*
    * x and y must be numeric.  Save the cvnum return values for later use.
    */
   if ((t1 = cvnum(&Arg1, &n1)) == NULL)
      runerr(102, &Arg1);
   if ((t2 = cvnum(&Arg2, &n2)) == NULL)
      runerr(102, &Arg2);

   if (!(t1 == T_Real || t2 == T_Real)) {
      /*
       * Both x and y are integers.  Perform integer exponentiation
       *  and place the result in Arg0 as the return value.
       */
      Mkint(ipow(n1.integer, n2.integer), &Arg0);
      }
   else {
      /*
       * Either x or y is real, convert the other to a real, perform
       *  real exponentiation and place the result in Arg0 as the
       *  return value.
       */
      if (!(t1 == T_Real))
         n1.real = n1.integer;
      if (!(t2 == T_Real))
         n2.real = n2.integer;
      if (n1.real == 0.0 && n2.real <= 0.0)
         /*
          * Tried to raise zero to a negative power.
          */
         runerr(204, NULL);
      if (n1.real < 0.0 && t2 == T_Real)
         /*
          * Tried to raise a negative number to a real power.
          */
         runerr(206, NULL);
      mkreal(pow(n1.real,n2.real), &Arg0);
      }
   Return;
   }

long ipow(n1, n2)
long n1, n2;
   {
   long result;

   if (n1 == 0 && n2 <= 0)
      runerr(204, NULL);
   if (n2 < 0)
      return 0.0;
   result = 1L;
   while (n2 > 0) {
      if (n2 & 01L)
         result *= n1;
      n1 *= n1;
      n2 >>= 1;
      }
   return result;
   }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.