code: /**
   * 
   */
  package edu.berkeley.nlp.util;
  
  import java.util.Arrays;
  
  import edu.berkeley.nlp.math.DoubleArrays;
  import edu.berkeley.nlp.math.SloppyMath;
  
  /**
   * @author petrov
   * 
   */
  public class ScalingTools {
  	// SCALING
  	public static final int LOGSCALE = 100;
  	public static final double SCALE = Math.exp(LOGSCALE);
  
  	// Note: e^709 is the largest double java can handle.
  
  	public static double calcScaleFactor(double logScale) {
  		return calcScaleFactor(logScale, SCALE);
  	}
  
  	public static double calcScaleFactor(double logScale, double scale) {
  		if (logScale == Integer.MIN_VALUE) {
  			return 0.0;// System.out.println("give me a break!");
  		}
  		if (logScale == 0.0)
  			return 1.0;
  		if (logScale == 1.0)
  			return scale;
  		if (logScale == 2.0)
  			return scale * scale;
  		if (logScale == 3.0)
  			return scale * scale * scale;
  		if (logScale == -1.0)
  			return 1.0 / scale;
  		if (logScale == -2.0)
  			return 1.0 / scale / scale;
  		if (logScale == -3.0)
  			return 1.0 / scale / scale / scale;
  		return Math.pow(scale, logScale);
  	}
  
  	public static int scaleArray(double[] scores, int previousScale) {
  		if (previousScale == Integer.MIN_VALUE) {
  			return previousScale;// System.out.println("give me a break!");
  		}
  		// if (true) return previousScale;
  		int logScale = 0;
  		double scale = 1.0;
  		double max = DoubleArrays.max(scores);
  		if (max == Double.POSITIVE_INFINITY) {
  			// System.out.println("Infinity");
  			return 0;
  		}
  		if (max == 0)
  			return previousScale;
  		while (max > SCALE) {
  			max /= SCALE;
  			scale *= SCALE;
  			logScale += 1;
  		}
  		while (max > 0.0 && max < 1.0 / SCALE) {
  			max *= SCALE;
  			scale /= SCALE;
  			logScale -= 1;
  		}
  		if (logScale != 0) {
  			for (int i = 0; i < scores.length; i++) {
  				scores[i] /= scale;
  			}
  		}
  		// if (SloppyMath.isDangerous(ArrayMath.max(scores))){
  		// System.out.println("Undeflow when scaling scores!");
  		// }
  		return previousScale + logScale;
  	}
  
  	public static void scaleArrayToScale(double[] scores, int previousScale,
  			int newScale) {
  		int scaleDiff = previousScale - newScale;
  		if (scaleDiff == 0)
  			return; // nothing to do
  		double max = DoubleArrays.max(scores);
  		if (SloppyMath.isDangerous(max))
  			return;
  
  		double scale = calcScaleFactor(scaleDiff);
  
  		if (Math.abs(scaleDiff) >= 800) {
  			// under-/overflow...
  			Arrays.fill(scores, 0.0);
  			return;
  		}
  
  		for (int i = 0; i < scores.length; i++) {
  			scores[i] *= scale;
  		}
  		// if (SloppyMath.isDangerous(ArrayMath.max(scores))){
  		// System.out.println("Undeflow when scaling scores!");
  		// }
  	}
  
  	public static double scaleToScale(double score, int previousScale,
  			int newScale) {
  		int scaleDiff = previousScale - newScale;
  		if (scaleDiff == 0)
  			return score; // nothing to do
  		double max = score;
  
  		if (SloppyMath.isDangerous(max))
  			return 0;
  
  		double scale = calcScaleFactor(scaleDiff);
  
  		if (Math.abs(scaleDiff) >= 800) {
  			// under-/overflow...
  			return 0;
  		}
  
  		score *= scale;
  
  		return score;
  	}
  
  	public static boolean isBadScale(int scale) {
  		return scale == Integer.MIN_VALUE || scale == Integer.MAX_VALUE
  				|| scale == Integer.MAX_VALUE - 1
  				|| scale == Integer.MIN_VALUE + 1
  				|| scale == Integer.MAX_VALUE - 2
  				|| scale == Integer.MIN_VALUE + 2;
  	}
  
  }
  