DoubleIntervalNumber.java

/*
 * Created on 2004/04/23
 *
 * Copyright (C) 2004 Koga Laboratory. All rights reserved.
 */
package org.mklab.cga.interval.scalar;

import java.math.BigDecimal;

import org.mklab.cga.interval.function.DoubleLogVerifier;
import org.mklab.cga.interval.matrix.DoubleComplexIntervalMatrix;
import org.mklab.cga.interval.matrix.DoubleIntervalMatrix;
import org.mklab.cga.number.DoublePrecisionNumber;
import org.mklab.nfc.matrix.DoubleComplexMatrix;
import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.random.RandomGenerator;
import org.mklab.nfc.scalar.AbstractScalar;
import org.mklab.nfc.scalar.DoubleComplexNumber;
import org.mklab.nfc.scalar.DoubleNumber;
import org.mklab.nfc.scalar.DoubleNumberUtil;
import org.mklab.nfc.util.RoundMode;
import org.mklab.nfc.util.RoundModeManager;


/**
 * 倍精度の実数の区間を表すクラスです。
 * 
 * @author Hiroki
 * @version $Revision: 1.56 $, 2008/01/10
 */
public class DoubleIntervalNumber extends AbstractIntervalScalar<DoubleIntervalNumber,DoubleIntervalMatrix,DoubleNumber,DoubleMatrix> implements IntervalRealNumericalScalar<DoubleIntervalNumber,DoubleIntervalMatrix,DoubleComplexIntervalNumber,DoubleComplexIntervalMatrix,DoubleNumber,DoubleMatrix,DoubleComplexNumber,DoubleComplexMatrix> {

  /** シリアル番号 */
  private static final long serialVersionUID = -8235127548742875659L;

  /** 区間の下限 */
  private double infimum;

  /** 区間の上限 */
  private double supremum;

  /** 区間の中心 */
  private double middle;

  /** 区間の半径 */
  private double radius;

  /**
   * Creates {@link DoubleIntervalNumber}.
   * 
   * @param middle middle
   */
  public DoubleIntervalNumber(final double middle) {
    this(middle, middle);
  }

  /**
   * Creates {@link DoubleIntervalNumber}.
   * @param infimum 下限
   * @param suppremum 上限
   */
  public DoubleIntervalNumber(final double infimum, final double suppremum) {
    this.infimum = infimum;
    this.supremum = suppremum;
    this.middle = middle(this.infimum,this.supremum);
    this.radius = radius(this.infimum,this.supremum);
  }
  
  /**
   * 数値入力による誤差を考慮して区間を作ります。
   * 
   * @param middle 点
   * @param flag フラグ
   * @return interval
   */
  public static DoubleIntervalNumber createForInputError(final double middle, final boolean flag) {
    if (flag) {
      double inf = Math.nextAfter(middle, Double.NEGATIVE_INFINITY);
      double sup= Math.nextUp(middle);
      return new DoubleIntervalNumber(inf, sup);
    } 
    return new DoubleIntervalNumber(middle);
  }

  /**
   * 数値入力による誤差を考慮して区間を作ります。
   * 
   * @param inf 下限
   * @param sup 上限
   * @param flag フラグ
   * @return interval
   */
  public static DoubleIntervalNumber createForInputError(final double inf, final double sup, final boolean flag) {
    if (flag) {
      double inf2 = Math.nextAfter(inf, Double.NEGATIVE_INFINITY);
      double sup2 = Math.nextUp(sup);
      return new DoubleIntervalNumber(inf2, sup2);
    } 

    return new DoubleIntervalNumber(inf,sup);
  }

  /**
   * コンストラクタ。
   * 
   * 文字列として得られた実数をもとに、下限と上限を設定します。中心と半径は、下限と上限から計算されます。 String型-&gt;Double型に変換
   * 
   * @param stringValue 実数の文字列
   * @return interval
   * @throws IllegalArgumentException 例外引数
   */
  public static DoubleIntervalNumber create(final String stringValue) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    /*-- Create interval --*/
    if (stringValue.charAt(0) == '-') {
      manager.setRoundMode(RoundMode.ROUND_UP);
      double inf = translateFromStringToDouble(stringValue);
      manager.setRoundMode(RoundMode.ROUND_DOWN);
      double sup = translateFromStringToDouble(stringValue);
      manager.setRoundMode(oldRoundMode);
      return new DoubleIntervalNumber(inf, sup);
    }

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = translateFromStringToDouble(stringValue);
    manager.setRoundMode(RoundMode.ROUND_UP);
    manager.setRoundMode(oldRoundMode);
    double sup = translateFromStringToDouble(stringValue);
    return new DoubleIntervalNumber(inf,sup);
  }

  /**
   * コンストラクタ。
   * 
   * 文字列として得られた実数をもとに、下限と上限を設定します。中心と半径は、下限と上限から計算されます。 String型-&gt;Double型に変換
   * 
   * @param stringInfimum 下限
   * @param stringSupremum 上限
   * @return interval
   */
  public static DoubleIntervalNumber create(final String stringInfimum, final String stringSupremum) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    final double inf;
    
    // set this.infimum
    if (stringInfimum.charAt(0) == '-') {
      manager.setRoundMode(RoundMode.ROUND_UP);
      inf= translateFromStringToDouble(stringInfimum);
    } else {
      manager.setRoundMode(RoundMode.ROUND_DOWN);
      inf= translateFromStringToDouble(stringInfimum);
    }

    final double sup;
    
    // set this.supremum
    if (stringSupremum.charAt(0) == '-') {
      manager.setRoundMode(RoundMode.ROUND_DOWN);
      sup = translateFromStringToDouble(stringSupremum);
    } else {
      manager.setRoundMode(RoundMode.ROUND_UP);
      sup = translateFromStringToDouble(stringSupremum);
    }

    manager.setRoundMode(oldRoundMode);
    
    return new DoubleIntervalNumber(inf,sup);
  }

  /**
   * String型からdouble型への変換
   * 
   * @param stringValue String型実数
   * @return double
   * @throws IllegalArgumentException 例外
   */
  private static double translateFromStringToDouble(final String stringValue) {
    String strValue = stringValue;
    boolean negativeSign = false;
    String strPower10 = null;
    int power10 = 0;
    int arithmeticPoint = 0;
    long integralNumber = 0;
    double realNumber = 0.0;

    try {
      /*-- Check sign --*/
      if (strValue.charAt(0) == '-') {
        strValue = strValue.substring(1);
        negativeSign = true;
      }

      /*-- Check E(n) (E(n) = 10^n) --*/
      if (strValue.indexOf('e') != -1) {
        strPower10 = strValue.substring(strValue.indexOf('e') + 1);
        strValue = strValue.substring(0, strValue.indexOf('e'));

        if (strPower10.charAt(0) == '-') {
          strPower10 = strPower10.substring(1);
          power10 = -1 * Integer.parseInt(strPower10);
        } else {
          power10 = Integer.parseInt(strPower10);
        }

      } else if (strValue.indexOf('E') != -1) {
        strPower10 = strValue.substring(strValue.indexOf('E') + 1);
        strValue = strValue.substring(0, strValue.indexOf('E'));

        if (strPower10.charAt(0) == '-') {
          strPower10 = strPower10.substring(1);
          power10 = -1 * Integer.parseInt(strPower10);
        } else {
          power10 = Integer.parseInt(strPower10);
        }
      }

      /*-- Check index of arithmetic point --*/

      if (strValue.indexOf('.') != -1) {
        arithmeticPoint = strValue.length() - strValue.indexOf('.') - 1;

        StringBuilder strValueNonPoint = new StringBuilder(strValue);
        strValueNonPoint = strValueNonPoint.deleteCharAt(strValueNonPoint.indexOf(".")); //$NON-NLS-1$

        strValue = strValueNonPoint.toString();
      }

      /*-- Search powers of 10 --*/
      power10 -= arithmeticPoint;

      /*-- Get from under digit --*/
      char[] charArray = new char[strValue.length()];
      for (int i = 0; i < strValue.length(); i++) {
        charArray[i] = strValue.charAt(strValue.length() - i - 1);
      }

      /*-- Translate from string to integer --*/
      for (int j = 0; j < strValue.length(); j++) {
        integralNumber += (Long.parseLong("" + charArray[j]) * Math.pow(10, j)); //$NON-NLS-1$
      }

      /*-- Calculate real number --*/
      if (power10 >= 0) {
        realNumber = integralNumber * Math.pow(10, power10);
      } else {
        power10 = -power10;
        realNumber = integralNumber / Math.pow(10, power10);
      }

      if (negativeSign == true) {
        realNumber = -realNumber;
      }

      if ((realNumber < -Math.pow(10, 308)) && (realNumber > Math.pow(10, 308))) {
        throw new IllegalArgumentException("Input beyond range of double-type."); //$NON-NLS-1$
      }
    } catch (@SuppressWarnings("unused") IllegalArgumentException e) {
      System.out.println("Input is illegal."); //$NON-NLS-1$
    }
    return realNumber;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber create(final int value) {
    return new DoubleIntervalNumber(value);
  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber create(double value) {
    return new DoubleIntervalNumber(value);
  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber create(DoubleNumber value) {
    return new DoubleIntervalNumber(value.doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber createInfSup(DoubleNumber inf, DoubleNumber sup) {
    return new DoubleIntervalNumber(inf.doubleValue(), sup.doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber createMidRad(DoubleNumber mid, DoubleNumber rad) {
    return new DoubleIntervalNumber(infimum(mid.doubleValue(), rad.doubleValue()), supremum(mid.doubleValue(), rad.doubleValue()));
  }

  /**
   * Creates interval
   * 
   * @param mid middle
   * @param rad radius
   * @return interval
   */
  public static DoubleIntervalNumber createMiddleRadius(DoubleNumber mid, DoubleNumber rad) {
    return new DoubleIntervalNumber(infimum(mid.doubleValue(), rad.doubleValue()), supremum(mid.doubleValue(), rad.doubleValue()));
  }
  
  /**
   * Creates interval
   * 
   * @param inf infimum
   * @param sup supremum
   * @return interval
   */
  public static DoubleIntervalNumber createInfimumSupremum(DoubleNumber inf, DoubleNumber sup) {
    return new DoubleIntervalNumber(inf.doubleValue(), sup.doubleValue());
  }


  /**
   * {@inheritDoc}
   */
  public DoubleNumber getInfimum() {
    return new DoubleNumber(this.infimum);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleNumber getSupremum() {
    return new DoubleNumber(this.supremum);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleNumber getMiddle() {
    return new DoubleNumber(this.middle);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleNumber getRadius() {
    return new DoubleNumber(this.radius);
  }

//  /**
//   * {@inheritDoc}
//   */
//  public DoubleIntervalNumber add(final DoubleIntervalNumber interval) {// IR+IR, IR+IC
//    if (interval instanceof DoubleIntervalNumber) {// IR+IR
//      return add((DoubleIntervalNumber)interval);
//    }
//    if (interval instanceof DoubleComplexIntervalNumber) {// IR+IC
//      return add((DoubleComplexIntervalNumber)interval);
//    }
//    if (interval instanceof NumericalIntervalScalar) {
//      return add((NumericalIntervalScalar<?>)interval);
//    }
//
//    throw new RuntimeException("Not implemented."); //$NON-NLS-1$
//  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber add(final DoubleIntervalNumber interval) {// IR+IR
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = this.infimum + interval.getInfimum().doubleValue();

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = this.supremum + interval.getSupremum().doubleValue();

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

//  /**
//   * 自身と複素数区間との和を求めます。
//   * 
//   * @param interval 複素数区間
//   * @return 和
//   */
//  public DoubleComplexIntervalNumber add(final DoubleComplexIntervalNumber interval) {// IR+IC
//    RoundModeManager manager = RoundModeManager.getManager();
//    RoundMode oldRoundMode = manager.getRoundMode();
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    DoubleComplexNumber c1 = new DoubleComplexNumber(this.middle, 0).add(interval.getMiddle());
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    DoubleComplexNumber mid = new DoubleComplexNumber(this.middle, 0).add(interval.getMiddle());
//
//    double rad = mid.subtract(c1).add(this.radius).getRealPart().doubleValue();
//    rad = rad + this.radius;
//    rad = rad + interval.getRadius().doubleValue();
//
//    manager.setRoundMode(oldRoundMode);
//    return new DoubleComplexIntervalNumber(mid, rad);
//  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber add(final DoubleNumber d) {// IR+R
    return add(d.doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber add(final double d) {// IR+R
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = this.infimum + d;

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = this.supremum + d;

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

//  /**
//   * {@inheritDoc}
//   */
//  public DoubleComplexIntervalNumber add(final DoubleComplexNumber c) {// IR+C
//    RoundModeManager manager = RoundModeManager.getManager();
//    RoundMode oldRoundMode = manager.getRoundMode();
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    DoubleComplexNumber c1 = new DoubleComplexNumber(this.middle, 0).add(c);
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    DoubleComplexNumber mid = new DoubleComplexNumber(this.middle, 0).add(c);
//
//    double rad = mid.subtract(c1).abs().doubleValue() + this.radius;
//
//    manager.setRoundMode(oldRoundMode);
//    return new DoubleComplexIntervalNumber(mid, rad);
//  }

//  /**
//   * @see org.mklab.cga.interval.scalar.IntervalScalar#subtract(org.mklab.cga.interval.scalar.IntervalScalar)
//   */
//  public IntervalScalar<?> subtract(final IntervalScalar<?> interval) {// IR-IR, IR-IC
//    if (interval instanceof DoubleIntervalNumber) {// IR-IR
//      return subtract((DoubleIntervalNumber)interval);
//    }
//    if (interval instanceof DoubleComplexIntervalNumber) {// IR-IC
//      return subtract((DoubleComplexIntervalNumber)interval);
//    }
//    if (interval instanceof NumericalIntervalScalar) {
//      return subtract((NumericalIntervalScalar<?>)interval);
//    }
//
//    throw new RuntimeException("Not implemented."); //$NON-NLS-1$
//  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber subtract(final DoubleIntervalNumber interval) {// IR-IR
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = this.infimum - interval.getSupremum().doubleValue();

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = this.supremum - interval.getInfimum().doubleValue();

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

//  /**
//   * 自身と複素数区間との差を求めます。
//   * 
//   * @param interval 複素数区間。
//   * @return 差。
//   */
//  public DoubleComplexIntervalNumber subtract(final DoubleComplexIntervalNumber interval) {// IR-IC
//    RoundModeManager manager = RoundModeManager.getManager();
//    RoundMode oldRoundMode = manager.getRoundMode();
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    DoubleComplexNumber c1 = new DoubleComplexNumber(this.middle, 0).subtract(interval.getMiddle());
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    DoubleComplexNumber mid = new DoubleComplexNumber(this.middle, 0).subtract(interval.getMiddle());
//
//    double rad = mid.subtract(c1).abs().doubleValue();
//    rad = rad + this.radius;
//    rad = rad + interval.getRadius().doubleValue();
//
//    manager.setRoundMode(oldRoundMode);
//    return new DoubleComplexIntervalNumber(mid, rad);
//  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber subtract(final DoubleNumber d) {
    return subtract(d.doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber subtract(final double d) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = this.infimum - d;

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = this.supremum - d;

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

//  /**
//   * @see org.mklab.cga.interval.scalar.IntervalScalar#subtract(org.mklab.nfc.scalar.DoubleComplexNumber)
//   */
//  public DoubleComplexIntervalNumber subtract(final DoubleComplexNumber c) {
//    RoundModeManager manager = RoundModeManager.getManager();
//    RoundMode oldRoundMode = manager.getRoundMode();
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    DoubleComplexNumber c1 = new DoubleComplexNumber(this.middle, 0).subtract(c);
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    DoubleComplexNumber mid = new DoubleComplexNumber(this.middle, 0).subtract(c);
//
//    double rad = mid.subtract(c1).abs().doubleValue() + this.radius;
//
//    manager.setRoundMode(oldRoundMode);
//    return new DoubleComplexIntervalNumber(mid, rad);
//  }

//  /**
//   * @see org.mklab.cga.interval.scalar.IntervalScalar#multiply(org.mklab.cga.interval.scalar.IntervalScalar)
//   */
//  public IntervalScalar<?> multiply(final IntervalScalar<?> interval) {// IR*IR, IR*IC
//    if (interval instanceof DoubleIntervalNumber) {// IR*IR
//      return multiply((DoubleIntervalNumber)interval);
//    }
//    if (interval instanceof DoubleComplexIntervalNumber) {// IR*IC
//      return multiply((DoubleComplexIntervalNumber)interval);
//    }
//    if (interval instanceof NumericalIntervalScalar) {
//      return multiply((NumericalIntervalScalar<?>)interval);
//    }
//
//    throw new RuntimeException("Not implemented."); //$NON-NLS-1$
//  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber multiply(final DoubleIntervalNumber interval) {// IR*IR
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    double xi = this.infimum;
    double xs = this.supremum;

    double yi = interval.getInfimum().doubleValue();
    double ys = interval.getSupremum().doubleValue();

    //    manager.setRoundMode(RoundMode.ROUND_UP);
    //    double xc = (xs + xi) / 2; // アルファ中心
    //    double xr = xc - xi; // シータ半径
    //    double yc = (ys + yi) / 2; // ベータ
    //    double yr = yc - yi; // ガンマ
    //
    //    double sup = xc * yc + Math.abs(xc) * yr + Math.abs(yc) * xr + xr * yr;
    //
    //    manager.setRoundMode(RoundMode.ROUND_DOWN);
    //    double inf = xc * yc + (-Math.abs(xc) * yr + (-Math.abs(yc)) * xr + (-xr) * yr);

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.min(xi * yi, xi * ys);
    inf = Math.min(inf, xs * yi);
    inf = Math.min(inf, xs * ys);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.max(xi * yi, xi * ys);
    sup = Math.max(sup, xs * yi);
    sup = Math.max(sup, xs * ys);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

//  /**
//   * 自身と複素数区間との積を求めます。
//   * 
//   * @param interval 複素数区間。
//   * @return 積。
//   */
//  public DoubleComplexIntervalNumber multiply(final DoubleComplexIntervalNumber interval) {// IR*IC
//    RoundModeManager manager = RoundModeManager.getManager();
//    RoundMode oldRoundMode = manager.getRoundMode();
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    DoubleComplexNumber c1 = new DoubleComplexNumber(this.middle, 0).multiply(interval.getMiddle());
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    DoubleComplexNumber c2 = new DoubleComplexNumber(this.middle, 0).multiply(interval.getMiddle());
//    DoubleComplexNumber mid = c1.add(c2.subtract(c1).divide(2));
//    double rad;
//
//    if (this.radius == 0) {
//      if (interval.getRadius().isZero()) {
//        rad = mid.subtract(c1).abs().doubleValue();
//      } else {
//        rad = mid.subtract(c1).abs().doubleValue() + Math.abs(this.middle) * interval.getRadius().doubleValue();
//      }
//    } else if (interval.getRadius().isZero()) {
//      rad = mid.subtract(c1).abs().doubleValue() + this.radius * interval.getMiddle().abs().doubleValue();
//    } else {
//      rad = mid.subtract(c1).abs().doubleValue() + this.radius * (interval.getMiddle().abs().doubleValue() + interval.getRadius().doubleValue()) + Math.abs(this.middle)
//          * interval.getRadius().doubleValue();
//    }
//
//    manager.setRoundMode(oldRoundMode);
//    return new DoubleComplexIntervalNumber(mid, rad);
//  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber multiply(final DoubleNumber d) {// IR*R
    return multiply(d.doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber multiply(final double d) {// IR*R
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    //    manager.setRoundMode(RoundMode.ROUND_UP);
    //    double rad = this.radius * Math.abs(d);
    //    double sup = this.middle * d + rad;
    //
    //    manager.setRoundMode(RoundMode.ROUND_DOWN);
    //    double inf = this.middle * d - rad;

    double xi = this.infimum;
    double xs = this.supremum;

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.min(xi * d, xs * d);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.max(xi * d, xs * d);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

//  /**
//   * @see org.mklab.cga.interval.scalar.IntervalScalar#multiply(org.mklab.nfc.scalar.DoubleComplexNumber)
//   */
//  public DoubleComplexIntervalNumber multiply(final DoubleComplexNumber c) {// IR*C
//    RoundModeManager manager = RoundModeManager.getManager();
//    RoundMode oldRoundMode = manager.getRoundMode();
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    DoubleComplexNumber c1 = new DoubleComplexNumber(this.middle, 0).multiply(c);
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    DoubleComplexNumber c2 = new DoubleComplexNumber(this.middle, 0).multiply(c);
//    DoubleComplexNumber mid = c1.add(c2.subtract(c1).divide(2));
//
//    double rad = mid.subtract(c1).abs().doubleValue() + this.radius * c.abs().doubleValue();
//
//    manager.setRoundMode(oldRoundMode);
//    return new DoubleComplexIntervalNumber(mid, rad);
//  }

//  /**
//   * @see org.mklab.cga.interval.scalar.IntervalScalar#divide(org.mklab.cga.interval.scalar.IntervalScalar)
//   */
//  public IntervalScalar<?> divide(final IntervalScalar<?> i) {// IR/IR IR/IC
//    if (i instanceof DoubleIntervalNumber) {// IR/IR
//      return divide((DoubleIntervalNumber)i);
//    }
//    if (i instanceof DoubleComplexIntervalNumber) {// IR/IC
//      return divide((DoubleComplexIntervalNumber)i);
//    }
//    if (i instanceof NumericalIntervalScalar) {
//      return divide((NumericalIntervalScalar<?>)i);
//    }
//
//    throw new RuntimeException("Not implemented."); //$NON-NLS-1$
//  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber divide(final DoubleIntervalNumber y) {// IR/IR
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    final double yi = y.getInfimum().doubleValue();
    final double ys = y.getSupremum().doubleValue();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.min(this.infimum / yi, this.infimum / ys);
    inf = Math.min(inf, this.supremum / yi);
    inf = Math.min(inf, this.supremum / ys);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.max(this.infimum / yi, this.infimum / ys);
    sup = Math.max(sup, this.supremum / yi);
    sup = Math.max(sup, this.supremum / ys);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

//  /**
//   * 自身と複素数区間との商を求めます。
//   * 
//   * @param interval 複素数区間
//   * @return 商
//   */
//  public DoubleComplexIntervalNumber divide(final DoubleComplexIntervalNumber interval) {// IR/IC
//    RoundModeManager manager = RoundModeManager.getManager();
//    RoundMode oldRoundMode = manager.getRoundMode();
//
//    double x = interval.getMiddle().getRealPart().doubleValue();
//    double y = interval.getMiddle().getImaginaryPart().doubleValue();
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    double Ninf = x * x + y * y + (-interval.getRadius().doubleValue()) * interval.getRadius().doubleValue();
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    double Nsup = x * x + y * y + (-interval.getRadius().doubleValue()) * interval.getRadius().doubleValue();
//    double x2 = Math.max(x / Ninf, x / Nsup);
//    double y2 = Math.max(y / Ninf, y / Nsup);
//
//    manager.setRoundMode(RoundMode.ROUND_DOWN);
//    double x1 = Math.min(x / Ninf, x / Nsup);
//    double y1 = Math.min(y / Ninf, y / Nsup);
//    DoubleComplexNumber c1 = new DoubleComplexNumber(x1, -y2);
//
//    manager.setRoundMode(RoundMode.ROUND_UP);
//    DoubleComplexNumber c2 = new DoubleComplexNumber(x2, -y1);
//    DoubleComplexNumber binv_mid = c1.add(c2.subtract(c1).divide(2));
//    double binv_rad = binv_mid.subtract(c1).abs().doubleValue() + interval.getRadius().doubleValue() / Ninf;
//
//    DoubleComplexIntervalNumber binv = new DoubleComplexIntervalNumber(binv_mid, binv_rad);
//    DoubleComplexIntervalNumber c = this.multiply(binv);
//
//    manager.setRoundMode(oldRoundMode);
//    return c;
//  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber sqrt() {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    // 平方根はIEEE754の規格で精度が保証されている
    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.sqrt(this.infimum);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.sqrt(this.supremum);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber sqr() {
    DoubleIntervalNumber abs = this.abs();
    return new DoubleIntervalNumber(abs.getInfimum().doubleValue() * abs.getInfimum().doubleValue(), abs.getSupremum().doubleValue() * abs.getSupremum().doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber acos() {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.acos(this.supremum);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.acos(this.infimum);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber asin() {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.asin(this.infimum);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.asin(this.supremum);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber atan() {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.atan(this.infimum);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.atan(this.supremum);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber exp() {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = Math.exp(this.infimum);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = Math.exp(this.supremum);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber log() {
    DoubleLogVerifier verifier = new DoubleLogVerifier(5);
    DoubleIntervalNumber ans = verifier.solve(this);
    return ans;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleNumber mig() {
    double c;
    
    if ((this.infimum <= 0 && 0 <= this.supremum) == false) {
      c = Math.min(Math.abs(this.infimum), Math.abs(this.supremum));
    } else {
      c = 0;
    }

    return new DoubleNumber(c);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber unaryMinus() {
    return new DoubleIntervalNumber(-this.supremum, -this.infimum);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber abs() {
    double inf_abs = Math.abs(this.infimum);
    double sup_abs = Math.abs(this.supremum);
    double min = Math.min(inf_abs, sup_abs);
    double max = Math.max(inf_abs, sup_abs);

    return new DoubleIntervalNumber(min, max);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleNumber getError() {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_UP);
    double ans = this.supremum - this.infimum;

    manager.setRoundMode(oldRoundMode);
    return new DoubleNumber(ans);
  }

  /**
   * {@inheritDoc}
   */
  public void printInfSup() {
    printInfSup("ans"); //$NON-NLS-1$
  }

  /**
   * {@inheritDoc}
   */
  public void printInfSup(final String name) {
    System.out.println(name + Messages.getString("RealInterval.0") + this.infimum); //$NON-NLS-1$
    System.out.println(name + Messages.getString("RealInterval.1") + this.supremum); //$NON-NLS-1$
  }

  /**
   * {@inheritDoc}
   */
  public void printInfSupByBit() {
    printInfSupByBit("ans"); //$NON-NLS-1$
  }

  /**
   * {@inheritDoc}
   */
  public void printInfSupByBit(final String name) {
    System.out.println(name + Messages.getString("RealInterval.2") + new DoublePrecisionNumber(this.infimum).getBits()); //$NON-NLS-1$
    System.out.println(name + Messages.getString("RealInterval.3") + new DoublePrecisionNumber(this.supremum).getBits()); //$NON-NLS-1$
  }

  /**
   * 半径をビット列で表示します。
   * 
   * @param name メッセージ。
   */
  public void printRadByBit(String name) {
    System.out.println(name + Messages.getString("RealInterval.4") + new DoublePrecisionNumber(this.radius).getBits()); //$NON-NLS-1$
  }

  /**
   * {@inheritDoc}
   */
  public void printInterval() {
    printInterval("ans"); //$NON-NLS-1$
  }

  /**
   * {@inheritDoc}
   */
  public void printInterval(final String name) {
    String valueFormat = AbstractScalar.getDefaultFormat();
    String inf = DoubleNumber.toString(this.infimum, valueFormat);
    String sup = DoubleNumber.toString(this.supremum, valueFormat);
    System.out.println(name + "(infimum,supremum) = [" + inf + " , " + sup + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    //System.out.println(name + "(infimum,supremum) = [" + this.infimum + " , " + this.supremum + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  }

  /**
   * Display interval based on floating-point number of double-type.
   */
  public void printBinaryInterval() {
    printBinaryInterval("ans"); //$NON-NLS-1$
  }

  /**
   * Display interval based on floating-point number of double-type.
   * 
   * @param name of interval
   */
  public void printBinaryInterval(final String name) {
    String infBinary = new DoublePrecisionNumber(this.infimum).getBits();
    String supBinary = new DoublePrecisionNumber(this.supremum).getBits();
    System.out.println("Binary." + name + "(infimum,supremum) = [" + infBinary + " , " + supBinary + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
  }

  /**
   * Display interval based on floating-point number of BigDecimal-type.
   */
  public void printIntervalBigDecimal() {
    printIntervalBigDecimal("ans"); //$NON-NLS-1$
  }

  /**
   * Display interval based on floating-point number of BigDecimal-type.
   * 
   * @param name of interval
   */
  public void printIntervalBigDecimal(final String name) {
    BigDecimal infBig = new BigDecimal(this.infimum);
    BigDecimal supBig = new BigDecimal(this.supremum);
    System.out.println("BigDecimal." + name + "(infimum,supremum) = [" + infBig + " , " + supBig + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
  }

  /**
   * {@inheritDoc}
   */
  public void printMidRad() {
    printMidRad("ans"); //$NON-NLS-1$
  }

  /**
   * {@inheritDoc}
   */
  public void printMidRad(final String name) {
    System.out.println(name + "(middle,radius) = <" + this.middle + " , " + this.radius + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  }

  /**
   * 区間の中心を求めます。
   * @param inf infimum
   * @param sup supremum
   * 
   * @return 区間の中心。
   */
  public static double middle(double inf, double sup) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_UP);
    double mid = inf+ (sup- inf)/ 2;

    manager.setRoundMode(oldRoundMode);
    return mid;
  }

  /**
   * 区間の半径を求めます。
   * @param inf infimum
   * @param sup supremum
   * 
   * @return 区間の半径。
   */
  public static double radius(double inf, double sup) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_UP);
    double mid = middle(inf,sup);
    double rad = mid - inf;

    manager.setRoundMode(oldRoundMode);
    return rad;
  }
  
  /**
   * 下限を求めます。
   * 
   * @param mid middle
   * @param rad radius
   * @return 下限
   */
  public static  double infimum(double mid, double rad) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);

    double inf = mid - rad;
    
    manager.setRoundMode(oldRoundMode);
    return inf;
  }
  
  /**
   * 上限を求めます。
   * 
   * @param mid middle
   * @param rad radius
   * @return 上限
   */
  public static double supremum(double mid, double rad) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_UP);

    double sup = mid + rad;

    manager.setRoundMode(oldRoundMode);
    return sup;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(this.infimum);
    result = prime * result + (int)(temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(this.middle);
    result = prime * result + (int)(temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(this.radius);
    result = prime * result + (int)(temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(this.supremum);
    result = prime * result + (int)(temp ^ (temp >>> 32));
    return result;
  }

  /**
   * 区間内に含まれる浮動小数点数の数を返します。
   * 
   * @return 区間内に含まれる浮動小数点数の数
   */
  public long getPointsNumber() {
    return DoublePrecisionNumber.getPointsNumber(this.infimum, this.supremum);
  }

  /**
   * 区間からcount番目の浮動小数点数を返します。
   * 
   * @param count 浮動小数点数の番号
   * @return 区間からcount番目の浮動小数点数
   */
  public double getPoint(long count) {
    return DoublePrecisionNumber.getPoint(this.infimum, this.supremum, count);
  }

  /**
   * 値が区間内で何番目の浮動小数かを返します。
   * 
   * @param value 区間内の値
   * @return valueの区間内での浮動小数点の番号
   */
  public long getPointOfValue(double value) {
    return DoublePrecisionNumber.getPointOfValue(this.infimum, this.supremum, value);
  }

  /**
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }

    final DoubleIntervalNumber other = (DoubleIntervalNumber)obj;

    if (this.infimum != other.infimum) {
      return false;
    }
    if (this.middle != other.middle) {
      return false;
    }
    if (this.radius != other.radius) {
      return false;
    }
    if (this.supremum != other.supremum) {
      return false;
    }

    return true;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber add(int value) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = this.infimum + value;

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = this.supremum + value;

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  //  /**
  //   * @see org.mklab.nfc.scalar.Scalar#addSelf(org.mklab.nfc.scalar.Scalar)
  //   */
  //  public Scalar<?> addSelf(Scalar<?> value) {
  //    RoundModeManager manager = RoundModeManager.getManager();
  //    RoundMode oldRoundMode = manager.getRoundMode();
  //    
  //    manager.setRoundMode(RoundMode.ROUND_DOWN);
  //    this.infimum = this.infimum + ((DoubleIntervalNumber)value).getInfimum().doubleValue();
  //    
  //    manager.setRoundMode(RoundMode.ROUND_UP);
  //    this.supremum = this.supremum + ((DoubleIntervalNumber)value).getSupremum().doubleValue();
  //
  //    manager.setRoundMode(oldRoundMode);
  //    return this;
  //  }

  /**
   * {@inheritDoc}
   */
  public boolean compare(String operator, int opponent) {
    if (operator.equals(".==")) { //$NON-NLS-1$
      if (this.infimum == opponent && this.supremum == opponent) {
        return true;
      }
      return false;
    }

    if (operator.equals(".!=")) { //$NON-NLS-1$
      if (this.infimum != opponent || this.supremum != opponent) {
        return true;
      }
      return false;
    }

    if (operator.equals(".<")) { //$NON-NLS-1$
      if (this.supremum < opponent) {
        return true;
      }
      return false;
    }

    if (operator.equals(".<=")) { //$NON-NLS-1$
      if (this.supremum <= opponent) {
        return true;
      }
      return false;
    }

    if (operator.equals(".>")) { //$NON-NLS-1$
      if (this.infimum > opponent) {
        return true;
      }
      return false;
    }

    if (operator.equals(".>=")) { //$NON-NLS-1$
      if (this.infimum >= opponent) {
        return true;
      }
      return false;
    }

    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public boolean compare(String operator, double opponent) {
    if (operator.equals(".!=")) { //$NON-NLS-1$
      if (this.infimum != opponent || this.supremum != opponent) {
        return true;
      }
    } else if (operator.equals(".==")) { //$NON-NLS-1$
      if (this.infimum == opponent && this.supremum == opponent) {
        return true;
      }
    } else if (operator.equals(".<")) { //$NON-NLS-1$
      if (this.supremum < opponent) {
        return true;
      }
    } else if (operator.equals(".<=")) { //$NON-NLS-1$
      if (this.supremum <= opponent) {
        return true;
      }
    } else if (operator.equals(".>")) { //$NON-NLS-1$
      if (this.infimum > opponent) {
        return true;
      }
    } else if (operator.equals(".>=")) { //$NON-NLS-1$
      if (this.infimum >= opponent) {
        return true;
      }
    } else {
      throw new UnsupportedOperationException();
    }

    return false;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber conjugate() {
    return this.clone();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalMatrix createGrid(int rowSize, int columnSize, DoubleIntervalNumber[][] elements) {
    return new DoubleIntervalMatrix(elements);
  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalMatrix createGrid(DoubleIntervalNumber[] elements) {
    return new DoubleIntervalMatrix(elements);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber createUnit() {
    return new DoubleIntervalNumber(1);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber divide(int value) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double cinf = Math.min(this.infimum / value, this.supremum / value);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double csup = Math.max(this.infimum / value, this.supremum / value);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(cinf, csup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber divide(DoubleNumber value) {
    return divide(value.doubleValue());
  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber divide(double value) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double cinf = Math.min(this.infimum / value, this.supremum / value);

    manager.setRoundMode(RoundMode.ROUND_UP);
    double csup = Math.max(this.infimum / value, this.supremum / value);

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(cinf, csup);
  }

  /**
   * {@inheritDoc}
   */
  public boolean equals(DoubleIntervalNumber opponent, double tolerance) {
    return Math.abs(this.infimum - opponent.infimum) <= tolerance && Math.abs(this.supremum - opponent.supremum) <= tolerance;
  }


  /**
   * {@inheritDoc}
   */
  public boolean equals(DoubleIntervalNumber opponent, DoubleIntervalNumber tolerance) {
    return equals(opponent, tolerance.getMiddle().doubleValue());
  }

  
  //  /**
  //   * @see org.mklab.nfc.scalar.Scalar#equals(org.mklab.nfc.scalar.Scalar, double)
  //   */
  //  @Override
  //  public boolean equals(Scalar<?> opponent, double tolerance) {
  //    if (opponent instanceof DoubleIntervalNumber) {
  //      return equals((DoubleIntervalNumber)opponent, tolerance);
  //    }
  //
  //    return super.equals(opponent, tolerance);
  //  }

//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getImaginaryPart()
//   */
//  public DoubleIntervalNumber getImaginaryPart() {
//    return this.createZero();
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#getRealPart()
//   */
//  public DoubleIntervalNumber getRealPart() {
//    return (DoubleIntervalNumber)this.clone();
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setRealPart(int)
//   */
//  public void setRealPart(int realPart) {
//    throw new UnsupportedOperationException("Not a complex number"); //$NON-NLS-1$
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setRealPart(double)
//   */
//  public void setRealPart(double realPart) {
//    throw new UnsupportedOperationException("Not a complex number"); //$NON-NLS-1$
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setRealPart(org.mklab.nfc.scalar.Scalar)
//   */
//  public void setRealPart(Scalar<?> realPart) {
//    throw new UnsupportedOperationException("Not a complex number"); //$NON-NLS-1$
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setImaginaryPart(int)
//   */
//  public void setImaginaryPart(int imagPart) {
//    throw new UnsupportedOperationException("Not a complex number"); //$NON-NLS-1$
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setImaginaryPart(double)
//   */
//  public void setImaginaryPart(double imagPart) {
//    throw new UnsupportedOperationException("Not a complex number"); //$NON-NLS-1$
//  }
//
//  /**
//   * @see org.mklab.nfc.scalar.Scalar#setImaginaryPart(org.mklab.nfc.scalar.Scalar)
//   */
//  public void setImaginaryPart(Scalar<?> imagPart) {
//    throw new UnsupportedOperationException("Not a complex number"); //$NON-NLS-1$
//  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber inverse() {
    return new DoubleIntervalNumber(Math.min(1 / this.supremum, 1 / this.infimum), Math.max(1 / this.supremum, 1 / this.infimum));
  }

  /**
   * {@inheritDoc}
   */
  public boolean isComplex() {
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isInfinite() {
    return Double.isInfinite(this.infimum) || Double.isInfinite(this.supremum);

  }

  /**
   * {@inheritDoc}
   */
  public boolean isNaN() {
    return Double.isNaN(this.infimum) || Double.isNaN(this.supremum);
  }

  /**
   * {@inheritDoc}
   */
  public boolean isReal() {
    return true;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isUnit() {
    return this.infimum == 1 && this.supremum == 1;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isUnit(double tolerance) {
    return Math.abs(this.infimum - 1.0) < tolerance && Math.abs(this.supremum - 1.0) < tolerance;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isUnit(DoubleIntervalNumber tolerance) {
    return tolerance.isGreaterThanOrEquals(Math.abs(this.infimum - 1.0)) && tolerance.isGreaterThanOrEquals(Math.abs(this.supremum - 1.0));
  }

  /**
   * {@inheritDoc}
   */
  public boolean isZero(double tolerance) {
    return Math.abs(this.infimum) <= tolerance && Math.abs(this.supremum) <= 0;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isZero(DoubleIntervalNumber tolerance) {
    return tolerance.isGreaterThanOrEquals(Math.abs(this.infimum)) && tolerance.isGreaterThanOrEquals(Math.abs(this.supremum));
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber leftDivide(int value) {
    return this.inverse().multiply(value);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber leftDivide(DoubleNumber value) {
    return leftDivide(value.doubleValue());
  }
  
  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber leftDivide(double value) {
    return this.inverse().multiply(value);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber multiply(int value) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    double localMiddle = this.middle * value;

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double localInfimum = localMiddle + this.radius;

    manager.setRoundMode(RoundMode.ROUND_UP);
    double localSupremum = localMiddle + this.radius;

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(localInfimum, localSupremum);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber power(int scalar) {
    DoubleIntervalNumber value = this.create(1);
    if (scalar == 0) {
      return value;
    }
    for (int i = 0; i < scalar; i++) {
      value = value.multiply(this);
    }
    return value;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber subtract(int value) {
    RoundModeManager manager = RoundModeManager.getManager();
    RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    double inf = this.infimum - value;

    manager.setRoundMode(RoundMode.ROUND_UP);
    double sup = this.supremum - value;

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber toComplex() {
    return new DoubleComplexIntervalNumber(new DoubleComplexNumber(this.middle), new DoubleNumber(this.radius));
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("boxing")
  public String toString(String valueFormat) {
    return String.format("(" + valueFormat + "," + valueFormat + ")", this.infimum, this.supremum); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber[] createArray(int size) {
    return new DoubleIntervalNumber[size];
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber[][] createArray(int rowSize, int columnSize) {
    return new DoubleIntervalNumber[rowSize][columnSize];
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber createZero() {
    return new DoubleIntervalNumber(0);
  }

  /**
   * {@inheritDoc}
   */
  public boolean isZero() {
    return this.infimum == 0 && this.supremum == 0;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber ceil() {
    return new DoubleIntervalNumber(Math.ceil(this.infimum), Math.ceil(this.supremum));
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber fix() {
    return new DoubleIntervalNumber(Math.ceil(this.infimum), Math.ceil(this.supremum));
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber floor() {
    return new DoubleIntervalNumber(Math.floor(this.infimum), Math.floor(this.supremum));
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber round() {
    return new DoubleIntervalNumber(Math.rint(this.infimum), Math.rint(this.supremum));
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber roundToZero(double tolerance) {
    return new DoubleIntervalNumber(DoubleNumberUtil.roundToZero(this.infimum, tolerance), DoubleNumberUtil.roundToZero(this.supremum, tolerance));
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber roundToZero(DoubleIntervalNumber tolerance) {
    double doubleTolerance = tolerance.getMiddle().doubleValue();
    return new DoubleIntervalNumber(DoubleNumberUtil.roundToZero(this.infimum, doubleTolerance), DoubleNumberUtil.roundToZero(this.supremum, doubleTolerance));
  }

  /**
   * 中心と半径を設定し、区間を作成します。
   * 
   * @param mid 中心
   * @param rad 半径
   * @return 区間
   */
  public static DoubleIntervalNumber createWithMiddleRadius(final double mid, final double rad) {
    final RoundModeManager manager = RoundModeManager.getManager();
    final RoundMode oldRoundMode = manager.getRoundMode();

    manager.setRoundMode(RoundMode.ROUND_DOWN);
    final double inf = mid - rad;

    manager.setRoundMode(RoundMode.ROUND_UP);
    final double sup = mid + rad;

    manager.setRoundMode(oldRoundMode);
    return new DoubleIntervalNumber(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public boolean isPointScalar() {
    return this.radius == 0;
  }

  /**
   * {@inheritDoc}
   */
  public boolean contains(double point) {
    if (getInfimum().isGreaterThan(point)) {
      return false;
    }
    
    if (getSupremum().isLessThan(point)) {
      return false;
      }

    return true;
  }

  /**
   * {@inheritDoc}
   */
  public boolean contains(DoubleNumber point) {
    return contains(point.doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber leftDivide(DoubleIntervalNumber value) {
    return this.inverse().multiply(value);
  }

  /**
   * {@inheritDoc}
   */
  public boolean compare(String operator, DoubleIntervalNumber opponent) {
    if (operator.equals(".!=")) { //$NON-NLS-1$
      if (this.infimum != opponent.getInfimum().doubleValue() || this.supremum != opponent.getSupremum().doubleValue()) {
        return true;
      }
    } else if (operator.equals(".==")) { //$NON-NLS-1$
      if (this.infimum == opponent.getInfimum().doubleValue()  && this.supremum == opponent.getSupremum().doubleValue()) {
        return true;
      }
    } else if (operator.equals(".<")) { //$NON-NLS-1$
      if (this.supremum < opponent.getInfimum().doubleValue()) {
        return true;
      }
    } else if (operator.equals(".<=")) { //$NON-NLS-1$
      if (this.supremum <= opponent.getInfimum().doubleValue()) {
        return true;
      }
    } else if (operator.equals(".>")) { //$NON-NLS-1$
      if (this.infimum > opponent.getSupremum().doubleValue()) {
        return true;
      }
    } else if (operator.equals(".>=")) { //$NON-NLS-1$
      if (this.infimum >= opponent.getSupremum().doubleValue()) {
        return true;
      }
    } else {
      throw new UnsupportedOperationException();
    }

    return false;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber abs2() {
    return abs().sqr();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber max(int value) {
    if (value < this.infimum) {
      return this;
    } else if (this.supremum < value) {
      return new DoubleIntervalNumber(value);
    }
    
    return this;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber max(double value) {
    if (value < this.infimum) {
      return this;
    } else if (this.supremum < value) {
      return new DoubleIntervalNumber(value);
    }
    
    return this;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber max(DoubleIntervalNumber value) {
    if (value.getSupremum().doubleValue() < this.infimum) {
      return this;
    }
    if (this.supremum < value.getInfimum().doubleValue()) {
      return value;
    }
    
    return this;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber min(int value) {
    if (this.supremum < value) {
      return this;
    }
    if (value < this.infimum) {
      return new DoubleIntervalNumber(value);
    }
    return this;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber min(double value) {
    if (this.supremum < value) {
      return this;
    }
    if (value < this.infimum) {
      return new DoubleIntervalNumber(value);
    }
    return this;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber min(DoubleIntervalNumber value) {
    if (this.supremum < value.getInfimum().doubleValue()) {
      return this;
    }
    if (value.getSupremum().doubleValue() < this.infimum) {
      return value;
    }
    return this;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber power(double scalar) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber power(DoubleIntervalNumber scalar) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber sin() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber sinh() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber asinh() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber cos() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber cosh() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber acosh() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber tan() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber tanh() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber atan2(DoubleIntervalNumber scalar) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber atan2(int scalar) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber atan2(double scalar) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber atanh() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber log10() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber remainder(DoubleIntervalNumber value2) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber remainder(int value2) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber remainder(double value2) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber modulus(int value2) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber modulus(double value2) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber modulus(DoubleIntervalNumber value2) {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public boolean isLessThan(DoubleIntervalNumber opponent) {
    if (this.supremum < opponent.getInfimum().doubleValue()) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isLessThanOrEquals(DoubleIntervalNumber opponent) {
    if (this.supremum <= opponent.getInfimum().doubleValue()) {
      return true;
    }

    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isGreaterThan(DoubleIntervalNumber opponent) {
    if (this.infimum > opponent.getSupremum().doubleValue()) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isGreaterThanOrEquals(DoubleIntervalNumber opponent) {
    if (this.infimum >= opponent.getSupremum().doubleValue()) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isLessThan(int opponent) {
    if (this.supremum < opponent) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isLessThan(double opponent) {
    if (this.supremum < opponent) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isLessThanOrEquals(int opponent) {
    if (this.supremum <= opponent) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isLessThanOrEquals(double opponent) {
    if (this.supremum <= opponent) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isGreaterThan(int opponent) {
    if (opponent < this.infimum) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isGreaterThan(double opponent) {
    if (opponent < this.infimum) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isGreaterThanOrEquals(int opponent) {
    if (opponent <= this.infimum) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isGreaterThanOrEquals(double opponent) {
    if (opponent <= this.infimum) {
      return true;
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber getMachineEpsilon() {
    return new DoubleIntervalNumber(DoubleNumber.EPS.doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber getInfinity() {
    return new DoubleIntervalNumber(new DoubleNumber(0).getInfinity().doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber getNaN() {
    return new DoubleIntervalNumber(new DoubleNumber(0).getNaN().doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber createPI() {
    return new DoubleIntervalNumber(new DoubleNumber(0).createPI().doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber createE() {
    return new DoubleIntervalNumber(new DoubleNumber(0).createE().doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public DoubleIntervalNumber valueOf(String numberString) {
    return new DoubleIntervalNumber(new DoubleNumber(0).valueOf(numberString).doubleValue());
  }

  /**
   * {@inheritDoc}
   */
  public RandomGenerator<DoubleIntervalNumber, DoubleIntervalMatrix> createUniformRandomGenerator() {
    throw new UnsupportedOperationException();
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber[] createComplexArray(DoubleIntervalNumber[] realPart, DoubleIntervalNumber[] imagPart) {
    final int size = realPart.length;
    DoubleComplexIntervalNumber[] ans = new DoubleComplexIntervalNumber[size];
    for (int i = 0; i < size; i++) {
      DoubleComplexNumber inf = new DoubleComplexNumber(realPart[i].getInfimum(), imagPart[i].getInfimum());
      DoubleComplexNumber sup = new DoubleComplexNumber(realPart[i].getSupremum(), imagPart[i].getSupremum());
      ans[i] = new DoubleComplexIntervalNumber(inf,sup);
    }
    return ans;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber[] createComplexArray(DoubleIntervalNumber[] realPart) {
    final int size = realPart.length;
    DoubleComplexIntervalNumber[] ans = new DoubleComplexIntervalNumber[size];
    for (int i = 0; i < size; i++) {
      DoubleComplexNumber inf = new DoubleComplexNumber(realPart[i].getInfimum());
      DoubleComplexNumber sup = new DoubleComplexNumber(realPart[i].getSupremum());
      ans[i] = new DoubleComplexIntervalNumber(inf,sup);
    }
    return ans;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber[][] createComplexArray(DoubleIntervalNumber[][] realPart, DoubleIntervalNumber[][] imagPart) {
    final int rowSize = realPart.length;
    final int columnSize = realPart[0].length;
    DoubleComplexIntervalNumber[][] ans = new DoubleComplexIntervalNumber[rowSize][columnSize];
    for (int i = 0; i < rowSize; i++) {
      for (int j = 0; j < columnSize; j++) {
        DoubleComplexNumber inf = new DoubleComplexNumber(realPart[i][j].getInfimum(), imagPart[i][j].getInfimum());
        DoubleComplexNumber sup = new DoubleComplexNumber(realPart[i][j].getSupremum(), imagPart[i][j].getSupremum());
        ans[i][j] = new DoubleComplexIntervalNumber(inf,sup);
      }
    }
    return ans;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber[][] createComplexArray(DoubleIntervalNumber[][] realPart) {
    final int rowSize = realPart.length;
    final int columnSize = realPart[0].length;
    DoubleComplexIntervalNumber[][] ans = new DoubleComplexIntervalNumber[rowSize][columnSize];
    for (int i = 0; i < rowSize; i++) {
      for (int j = 0; j < columnSize; j++) {
        DoubleComplexNumber inf = new DoubleComplexNumber(realPart[i][j].getInfimum());
        DoubleComplexNumber sup = new DoubleComplexNumber(realPart[i][j].getSupremum());
        ans[i][j] = new DoubleComplexIntervalNumber(inf,sup);
      }
    }
    return ans;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber createInfSup(DoubleComplexNumber inf, DoubleComplexNumber sup) {
    return DoubleComplexIntervalNumber.createInfimumSuppremum(inf, sup);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber createMidRad(DoubleComplexNumber mid, DoubleNumber rad) {
    return DoubleComplexIntervalNumber.createMiddleRadius(mid, rad);
  }

  /**
   * {@inheritDoc}
   */
  public double toDouble() {
    return this.middle;
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber add(DoubleComplexIntervalNumber value) {
    return toComplex().add(value);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber subtract(DoubleComplexIntervalNumber value) {
    return toComplex().subtract(value);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber multiply(DoubleComplexIntervalNumber value) {
    return toComplex().multiply(value);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber divide(DoubleComplexIntervalNumber value) {
    return toComplex().divide(value);
  }

  /**
   * {@inheritDoc}
   */
  public DoubleComplexIntervalNumber leftDivide(DoubleComplexIntervalNumber value) {
    return toComplex().leftDivide(value);
  }
}