// WalMath.js
/*
import com.wal.graph.Point2d;
import com.wal.util.PrintOut.*;
import com.wal.sort.IntQuickSort;
*/
//  ----------------------------------------------------------------------------
//  <p>Title: </p>
//  <p>Description: </p>
//  <p>Copyright: Copyright (c) 2003</p>
//  <p>Company: </p>
//  @author: Dr. Horst Walther
//  @version 1.65
//  ----------------------------------------------------------------------------

function WalMath () {
  var wordy = false;

//  ----------------------------------------------------------------------------
  this.sign = function (x) {
   return (x >= 0 ? 1 : -1) ;
  }

//  ----------------------------------------------------------------------------
  this.Exp10 = function (x) {
    return (x != 0.0 ? (Math.pow(10.0, Math.log(Math.abs(x)) * 10.0)) : 0.0);
  }

//  ----------------------------------------------------------------------------
  this.PotZer = function (x, Mantisse, Exponent) {
    var log10 = Log10(Math.abs(x));
    Exponent = 1.0 * (int) (log10);
    Mantisse = x - Exp10(Exponent);
  }

//  ----------------------------------------------------------------------------
  this.log2 = function (x) {
    var invLOG2 = 1.0 / Math.log(2);
    return (x > 0.0 ? (Math.log(x) * invLOG2) : 0.0);
  }

//  ----------------------------------------------------------------------------
  this.Log10 = function (x) {
    var invLOG10 = 1.0 / Math.log(10);
    return (x > 0.0 ? (Math.log(x) * invLOG10) : 0.0);
  }

//  ----------------------------------------------------------------------------
  this.mean = function (v) {
  }

//  ----------------------------------------------------------------------------
  this.mean = function (v, n) {
    if (n == undefined)
      return mean(v, v.length);
     n = (n <= 0) ? v.length : Math.min(n, v.length);
    var sum = 0.0;
    for (var i = 0; i < n; i++)
      sum += v[i];
    return sum / n;
  }

//  ----------------------------------------------------------------------------
  this.shiftMean = function (mean, minus, plus, n) {
    return mean - minus / n + plus / n;
  }

//  ----------------------------------------------------------------------------
  this.varianz  = function (v, mean) {
    var sum = 0.0;
    for (var i = 0; i < v.length; i++)
      sum += (v[i]-mean)*(v[i]-mean);
    return sum / v.length;
  }

//  ----------------------------------------------------------------------------
  this.shiftVarianz = function (varianz, meanOld, mean, minus, plus, n) {
    return varianz - (minus - meanOld) * (minus - meanOld) / n + (plus - mean) * (plus - mean) / n;
  }

//  ----------------------------------------------------------------------------
  this.coVarianz  = function (v1, dv2,  mean1, mean2) {
    var sum = 0.0;
    for (var i = 0; i < v1.length; i++)
      sum += (v1[i] - mean1) * (v2[i] - mean2);
    return sum / v1.length;
  }

//  ----------------------------------------------------------------------------
  this.corr = function (v1,v2) {
    if (v1.length != v2.length) {
      alert("### err: WalMath.corr: vectors differ in size, v1: (" + (v1.length) + ") not equal ("+ v2.length + ")");
      return 0.0;
    }
    var mean1 = mean(v1);
    var mean2 = mean(v2);
    var varianz1 = varianz(v1, mean1);
    var varianz2 = varianz(v2, mean2);
    var Cov12 = coVarianz (v1, v2, mean1, mean2);
    return Cov12 / (Math.sqrt(varianz1) * Math.sqrt(varianz2));
  }

//  ----------------------------------------------------------------------------
  this.iPotenz = function (d) {
    var i = 0;
    var neg = d < 1;
    if (neg) {
      var ref = 1;
      while ((ref * Math.abs(d)) < 1) {
        ref *= 10;
        i++;
      }
      return -i;
    }
    else {
      var ref = 10;
      var l = Math.abs(d);
      while (l > ref) {
        ref *= 10;
        i++;
      }
      return i;
    }
  }

//  ----------------------------------------------------------------------------
  this.mantisse = function (d, p) {
    var l = 1;
    var neg = p < 0;
    p = (neg ? -p : p);
    for (var i = 1; i <= p; i++)
      l *= 10;
    if (neg)
      return d * l;
    else
      return d / l;
  }

//  ----------------------------------------------------------------------------
  this.iPower10  = function (p) {
    var l = 1;
    for (var i=1; i<=p; i++)
      l *=10;
    return l;
  }

//  ----------------------------------------------------------------------------
  this.rwSmooth  = function (inPut, len) {
    len = Math.max (len, 1);
    var out = new Array (inPut.length);
    var mean = 0.0;
     for (var i = 0; i < inPut.length; i++) {
       mean = 0.0;
       for (var j = 0; j < Math.min(i+1, len); j++)
         mean += inPut[Math.max(0, i - j)];
       out[i] = mean /  Math.min(i+1, len);
     }
     return out;
  }

//  ----------------------------------------------------------------------------
  this.extrapol  = function (p1, p2, xExtra) {
    var a = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
    var b = p1.getY();
    return a*xExtra+b;
  }

//  ----------------------------------------------------------------------------
  this.fillAscending  = function (len) {
    var tmp = new Array [len];
    for (var i=0; i<len; i++)
      tmp[i] = i;
    return tmp;
  }

//  ----------------------------------------------------------------------------
  this.fill  = function (len, value) {
    var tmp = new Array [len];
    for (var i=0; i<len; i++)
      tmp[i] = value;
    return tmp;
  }

//  ----------------------------------------------------------------------------
  this.fill  = function (len, value) {
    var tmp = new Array [len];
    for (var i=0; i<len; i++)
      tmp[i] = value;
    return tmp;
  }

//  ----------------------------------------------------------------------------
  this.fill  = function (v, len, value) {
    for (var i=0; i<len; i++)
      v[i] = value;
    return v;
  }

//  ----------------------------------------------------------------------------
  this.sum = function (x) {
    var out = 0.0;
    for (var i = 0; i < x.length; i++)
      out += x[i];
    return out;
  }

//  ----------------------------------------------------------------------------
  this.sum = function (x) {
    return sum (x, x.length);
  }

//  ----------------------------------------------------------------------------
  this.sum = function (x, n) {
    var out = 0;
    for (var i = 0; i < n; i++)
      out += x[i];
    return out;
  }

//  ----------------------------------------------------------------------------
  this.calcZeroX  = function (x1, y1, x2, y2) {
    return calcZeroX(x1, y1, x2, y2, 0.0);
  }

//  ----------------------------------------------------------------------------
  this.calcZeroX  = function (x1, y1, x2, y2, y3) {
   var wordy = false;
   if (wordy) alert("calcTau: P1 = (" + x1 + "," + y1 + "), P2 = " + x2 + "," + y2 +  "," + y3 + ")");
     if (x2 == x1) return x1;
   var m = (y2 - y1) / (x2 - x1);
   var b = y1 - (m * x1);
   return ( y3 - b) / m;
 }

//  ----------------------------------------------------------------------------
  this.calcZeroX = function (indicator, x, y) {
   var xOut = new Array [indicator.length];
   for (var j = 0; j < indicator.length; j++) {
     if (SignChange(y[indicator[j]], y[indicator[j]+1]))
       xOut[j] = calcZeroX(x[indicator[j]]  , y[indicator[j]],
                           x[indicator[j]+1], y[indicator[j]+1]);
   }
   return xOut;
 }

//  ----------------------------------------------------------------------------
  this.IsMinimum = function (x, iMin, iMax, i) {
   var wordy = false;
   if (wordy) PrintOut.doubleVector(x, "Minimum-Suche ("+i+") in ...", 5);
   if ((i > iMin) && (i < iMax))
     if (x[i - 1] > x[i])
       if (x[i + 1] > x[i])
         return true;
       else
         return false;
     else
       return false;
   else
     return false;
 }

//  ----------------------------------------------------------------------------
 this.SignChange = function (x1, x2) {
   if ((x1 > 0.0) && (x2 > 0.0)) {
     return false;
   }
   else {
     if ((x1 <= 0.0) && (x2 <= 0.0)) {
       return false;
     }
     else {
       return true;
     }
   }
 }

//  ----------------------------------------------------------------------------
 this.trim = function (a, n) {
   var b = new Array [n];
   for (var i = 0; i < n; i++)
     b[i] = a[i];
   return b;
 }

//  ----------------------------------------------------------------------------
 this.max = function (a) {
   var b = a[0];
   for (var i = 1; i < a.length; i++)
     if  (a[i] > b)
       b = a[i];
   return b;
 }

//  ----------------------------------------------------------------------------
 this.min  = function (a) {
   var b = a[0];
   for (var i = 1; i < a.length; i++)
     if (a[i] < b)
       b = a[i];
   return b;
 }

//  ----------------------------------------------------------------------------
  this.doubleVec2String = function (vec) {
   var s = "";
   if (vec == null)
     return " null, ";
   for (var i = 0; i < vec.length; i++)
     s += vec[i] + ", ";
   return s;
 }

//  ----------------------------------------------------------------------------
 this.intVec2String = function (vec) {
   var s = "";
   if (vec == null)
     return " null, ";
   for (var i = 0; i < vec.length; i++)
     s += vec[i] + ", ";
   return s;
 }

//  ----------------------------------------------------------------------------
  this.isEqual  = function (v1, v2) {
    return isEqual (v1, v2, 0);
  }

//  ----------------------------------------------------------------------------
  this.isEqual  = function (v1, v2, i) {
//    alert(((long)(v1*100)+" == "+(long) (v2*100)));
//    alert (" = "+((long)(v1*100) == (long) (v2*100)));
    var ip = iPower10 (i);
    return ((v1*ip) == (v2*ip));
  }

//  ----------------------------------------------------------------------------
  this.countEquals = function (v, x) {
    return countEquals (v, x, 0);
  }

//  ----------------------------------------------------------------------------
  this.countEquals = function (v, x, ip) {
    var n = 0;
    for (var i = 0; i < x.length; i++)
      if (WalMath.isEqual(v, x[i], ip))
        n++;
//    alert("n = "+n);
    return n;
  }

//  ----------------------------------------------------------------------------
  this.countEquals = function (v, x) {
    var n = 0;
    for (var i = 0; i < x.length; i++)
      if (v == x[i])
        n++;
//    alert("n = "+n);
    return n;
  }

//  ----------------------------------------------------------------------------
  this.copy  = function (x) {
    var out = new Array [x.length];
    for (var i=0; i<x.length; i++)
      out[i] = x[i];
    return out;
  }

//  ----------------------------------------------------------------------------
  this.diff  = function (x, y) {
    var out = new Array [x.length];
    for (var i=0; i<x.length; i++)
      out[i] = x[i] - y[i];
    return out;
  }

//  ----------------------------------------------------------------------------
  this.copy  = function (from, to) {
    for (var i=0; i<from.length; i++)
      to[i] = from[i];
    return to;
  }

  //  ----------------------------------------------------------------------------
  this.push = function (x, xi) {
    for (var i = x.length - 1; i > 0; i--)
      x[i] = x[i - 1];
    x[0] = xi;
    return x;
  }

//  ----------------------------------------------------------------------------
  this.push = function (x, xi) {
    for (var i = x.length - 1; i > 0; i--)
      x[i] = x[i - 1];
    x[0] = xi;
    return x;
  }

//  ----------------------------------------------------------------------------
  this.copy = function (x) {
    var out = new Array (x.length);
    for (var i = 0; i < x.length; i++) {
      var tmp = new Array [x[i].length];
      for (var j = 0; j < x[i].length; j++)
        tmp[j] = x[i][j];
      out[i] = tmp;
    }
    return out;
  }

//  ----------------------------------------------------------------------------
  this.copy = function (x) {
    var out = new Array (x.length);
    for (var i = 0; i < x.length; i++) {
      var tmp = new Array [x[i].length];
      for (var j = 0; j < x[i].length; j++)
        tmp[j] = x[i][j];
      out[i] = tmp;
    }
    return out;
  }

//  ----------------------------------------------------------------------------
  this.search  = function (a, key) {
    return search (a, key, a.length-1);
  }

//  ----------------------------------------------------------------------------
  this.search = function (a, key, top) {
    var bot = 0;
//    alert("find " + key + " : ");
    if (key == a[top])
      return top;
    while (bot < top) { // non-empty range
      var mid = (bot + top) / 2; // mid-point
      if (key < a[mid]) { // key is lower
//        alert(", " + key + " < a[" + mid + "]");
        top = mid; //   adjust top
      }
      else if (key > a[mid]) { // key is higher
//        alert(", " + key + " < a[" + mid + "]");
        bot = mid + 1; //   adjust bottom
      }
      else {
//        alert(" = found: " + key + " at " + mid);
        return mid; // found
      }
    }
//    alert(", not found: " + key);
    return -1; // not found
  }

//  ----------------------------------------------------------------------------
  this.swap = function (a, i, j) {
    var b;
    b = a[i];
    a[i] = a[j];
    a[j] = b;
  }

//  ----------------------------------------------------------------------------
/*  this.sort = function (iX) {
    this.sorter = new IntQuickSort(iX) {

      function less(lo) {
        return (a[lo] < mid);
      }

      function more(hi) {
        return (a[hi] > mid);
      }

      function setMid() {
        mid = a[getMidIndex()];
      }
    };

    try {
      sorter.sort();
    }
    catch (ex) {
      alert("###  err: SimpleIntQuickSort.sort: oops, an error!");
    }
//    PrintOut.IntVector(iX, "iX sorted", 30);
    return iX;
  }*/

//  ----------------------------------------------------------------------------
//  Counts number decimal digits in a 32 bit signed number.
//  0 => 1, 9 => 1, 99 => 2, 2,147,483,647 => 10
//  @param x number whose digits you wish to count.
//  Must lie in range 0 .. Integer.MAX_VALUE;
//  @return number of digits in x, e.g. Integer.toString(x).length()
//  @author Marc Chappuis marnic@ludomedia.ch
  this.widthInDigits = function (x) {
// do an unravelled binary search
    if (x < 10000) {
      if (x < 100) {
        if (x < 10)
          return 1;
        else
          return 2;
      }
      else {
        if (x < 1000)
          return 3;
        else
          return 4;
      }
    }
    else {
      if (x < 1000000) {
        if (x < 100000)
          return 5;
        else
          return 6;
      }
      else {
        if (x < 100000000) {
          if (x < 10000000)
            return 7;
          else
            return 8;
        }
        else {
          if (x < 1000000000)
            return 9;
          else
            return 10;
        }
      }
    }
 }
 //  ----------------------------------------------------------------------------
}
