/*
  SUBROUTINE SCALE(FMN, FMX, N, VALMIN, STEP, VALMAX, IFAULT)
  
  ALGORITHM AS 96  APPL. STATIST. (1976) VOL.25, NO.1

  Given extreme values FMN, FMX, and the need for a scale with N
  marks, calculates value for the lowest scale mark (VALMIN) and
  step length (STEP) and highest scale mark (VALMAX).
*/

#include <math.h>

int scale(float fmn, float fmx, int n, float *valmin, float *step, float *valmax) {
 
  float unit[12]={0.0, 1.0, 1.2, 1.6, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0}; 
  int   i, j, ifault, nunit=11;;
  float tol=5.0e-6;
  float bias=1.0e-4;
  float fmax, fmin, rn, x, s, range;
 
  fmax=fmx;
  fmin=fmn;
  ifault=1;

  /* Test for valid parameter values */
  if ((fmax < fmin) || (n <= 1)) return(ifault);
  ifault=0;
  rn=(float)(n - 1.0);
  x=fabs(fmax);
  if (x == 0.0) x=1.0;
  if ((fmax-fmin)/x <= tol) {
    /* All values effectively equal */
    if (fmax < 0.0) fmax=0.0;
    else if (fmax == 0.0) fmax=1.0;
    else fmin=0.0;
  }
  *step=(fmax-fmin)/rn;
  s=*step;

  /* Find power of 10 */
  while (s<1.0) s*=10.0;
  while (s>=10.0) s/=10.0;

  /* Calculate STEP */
  x=s-bias;
  i=1;
  while ((i<=nunit) && (x>unit[i])) i++;
  *step=(*step)*unit[i]/s;
  range=(*step)*rn;

  /* Make first estimate of VALMIN */
  x=0.5 * (1.0 +(fmax+fmin-range)/(*step));
  j=(int)(x-bias);
  if (x<0.0) j--;
  *valmin=(*step)*(float)j;
  /* Test if VALMIN could be zero */
  if ((fmin >= 0.0) && (range >= fmax)) *valmin=0.0;
  *valmax=(*valmin)+range;
  
  /* Test if VALMAX could be zero */
  if ((fmax > 0.0) || (range < (-1)*fmin)) return(ifault);
  *valmax=0.0;
  *valmin=(-1)*range;
  return(ifault);
}

