/*****************************************************************************/
/* div32.c                                                                   */
/*                                                                           */
/* A program to divide one 32-bit signed binary number by another.           */
/*                                                                           */
/* Usage:  div32                                                             */
/*                                                                           */
/* Will divide 10 sets of numbers, and print out the results.                */
/*                                                                           */
/*****************************************************************************/

/************/
/* INCLUDES */
/************/

#include <stdio.h>

/***********/
/* DEFINES */
/***********/

#define ERROR -1
#define SUCCESS 0
#define TESTS 10

/***********************/
/* FUNCTION PROTOTYPES */
/***********************/

int div32 (long dividend, long divisor, long *quotient, long *remainder);

/************************/
/* FUNCTION DEFINITIONS */
/************************/

int main()
{
  /*
   *  Will test the following:
   *
   *  Divide by 0:  1 / 0
   *  Divide positive by negative:  9 / -4
   *  Divide negative by positive: -9 /  4
   *  Divide negative by negative: -9 / -4
   *  Use max as dividend:  2147483647 /  4
   *  Use max as divisor:   4 / 2147483647
   *  Use min as dividend: -2147483648 / 4
   *  Use min as divisor:  4 / -214783648
   *  Divide by 1: 4 / 1
   *  Divide by -1: 4 / -1
   */

  long dividend[TESTS] =
  {
    1,  9, -9, -9, 2147483647,         4, 0x80000000,           4, 4,  4
  };

  long divisor[TESTS] =
  {
    0, -4,  4, -4,          4, 2147483647,          4, 0x80000000, 1, -1
  };


  long quotient, remainder;
  int result, i;

  for (i = 0; i < TESTS; ++i)
  {
    printf("%d divided by %d ", dividend[i], divisor[i]);

    /* Divide the two numbers */
    result = div32 (dividend[i], divisor[i], &quotient, &remainder);

    if (result == ERROR)
    {
      printf("gives an error\n");
    }
    else
    {
      printf("is %d remainder %d\n", quotient, remainder);
    }
  }
  return 0;
}

/*****************************************************************************/
/* div32()                                                                   */
/*                                                                           */
/* Divide one 32-bit number by another                                       */
/*                                                                           */
/* Input:  dividend  - the number to divide                                  */
/*         divisor   - the number to divide by                               */
/* Output: quotient  - the result of the division                            */
/*         remainder - what remains after the division                       */
/*                                                                           */
/* Return Value: ERROR - division by zero attempted.                         */
/*               SUCCESS - the division worked.                              */
/*****************************************************************************/

int div32(long dividend, long divisor, long *quotient, long *remainder)
{
  int shifts, i, dividend_sign, divisor_sign;

  /* Check for divide by zero or 0x80000000 */
  if (divisor == 0 || divisor == 0x80000000 || dividend == 0x80000000)
  {
    return ERROR;
  }

  /* Check and remove signs from dividend and divisor */
  dividend_sign = 0;
  divisor_sign = 0;

  if (dividend < 0) {
    dividend_sign = 1;
    dividend = -dividend;
  }

  if (divisor < 0) {
    divisor_sign = 1;
    divisor = -divisor;
  }

  /* Initialization */
  shifts = 0;
  *remainder = dividend;
  *quotient = 0;

  /* Shift divisor until most significant bit is set */
  while ((divisor & 0x40000000) != 0x40000000) {
    divisor = divisor << 1;
    ++shifts;
  }

  /* Subtract and shift loop */
  for (i = 0; i <= shifts; ++i)
  {
    *quotient = *quotient << 1;
    if (*remainder - divisor >= 0)
    {
      *remainder -= divisor;
      *quotient += 1;
    }
    divisor = divisor >> 1;
  }

  /* Put the correct sign on the result */
  if (divisor_sign ^ dividend_sign)
  {
    *quotient = -*quotient;
  }

  if (dividend_sign)
  {
    *remainder = -*remainder;
  }

  return SUCCESS;
}