package dk.alexandra.fresco.lib.fixed;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import org.junit.Assert;

class FixedTestUtils {

  private FixedTestUtils() {
    // Should not be instantiated
  }

  static void assertEqual(BigDecimal a, BigDecimal b, int precision) {
    // TODO: Make relative to expected, eg. the number of correct bits
    BigDecimal bound = BigDecimal.ONE.setScale(precision, RoundingMode.HALF_UP)
        .divide(BigDecimal.valueOf(2.0).pow(precision), RoundingMode.HALF_UP);
    BigDecimal d = a.subtract(b).abs();
    Assert.assertTrue(a + " == " + b + " +/- 2^"
        + ceilLog2(d) + " but expected precision " + precision, d.compareTo(bound) <= 0);
  }

  static void assertEqual(double a, BigDecimal b, int precision) {
    assertEqual(BigDecimal.valueOf(a), b, precision);
  }

  static void assertEqual(List<BigDecimal> a, List<BigDecimal> b, int precision) {
    Assert.assertTrue("Lists must be of same size", a.size() == b.size());
    for (int i = 0; i < a.size(); i++) {
      assertEqual(a.get(i), b.get(i), precision);
    }
  }

  static int floorLog2(BigDecimal value) {
    return floorLog2(value.doubleValue());
  }

  static int floorLog2(double value) {
    return (int) Math.floor(Math.log(value) / Math.log(2.0));
  }
  
  static int ceilLog2(BigDecimal value) {
    return (int) Math.ceil(Math.log(value.doubleValue()) / Math.log(2.0));
  }
}
