BigDecimalIntervalNumber.java
/*
* Created on 2017/01/24
* Copyright (C) 2017 Koga Laboratory. All rights reserved.
*
*/
package org.mklab.cga.interval.scalar;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.mklab.nfc.util.RoundMode;
import org.mklab.nfc.util.RoundModeManager;
/**
* @author kenbishi
* @version $Revision$, 2017/03/01
*/
public class BigDecimalIntervalNumber {
/** 区間の下限 */
private BigDecimal infimum;
/** 区間の上限 */
private BigDecimal supremum;
/** 区間の中心 */
private BigDecimal middle;
/** 区間の半径 */
private BigDecimal radius;
/**
* コンストラクタ。 入力値を下限と上限に設定します。
*
* @param value 浮動小数点数
*/
public BigDecimalIntervalNumber(final String value) {
this.infimum = new BigDecimal(value);
this.supremum = new BigDecimal(value);
this.middle = mid();
this.radius = rad();
}
/**
* コンストラクタ。 下限と上限を設定します。
*
* @param inf 下限
* @param sup 上限
*/
public BigDecimalIntervalNumber(final String inf, final String sup) {
this.infimum = new BigDecimal(inf);
this.supremum = new BigDecimal(sup);
this.middle = mid();
this.radius = rad();
}
/**
* 数値入力による誤差を考慮して区間を作ります。
*
* @param value 点
* @param flag フラグ
*/
/*public BigDecimalCreateIntervalNumber(final double value, final boolean flag) {
if (flag) {
this.infimum = Math.nextAfter(value, Double.NEGATIVE_INFINITY);
this.supremum = Math.nextUp(value);
} else {
this.infimum = value;
this.supremum = value;
}
this.middle = mid();
this.radius = rad();
}*/
/**
* 数値入力による誤差を考慮して区間を作ります。
*
* @param inf 下限
* @param sup 上限
*/
/*public BigDecimalCreateIntervalNumber(final double inf, final double sup, final boolean flag) {
if (flag) {
this.infimum = Math.nextAfter(inf, Double.NEGATIVE_INFINITY);
this.supremum = Math.nextUp(sup);
} else {
this.infimum = inf;
this.supremum = sup;
}
this.middle = mid();
this.radius = rad();
}*/
public BigDecimalIntervalNumber(BigDecimal inf, BigDecimal sup) {
this.infimum = inf;
this.supremum = sup;
this.middle = mid();
this.radius = rad();
}
/**
* 区間の中心を求めます。
*
* @return 区間の中心。
*/
private BigDecimal mid() {
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal mid = this.infimum.add((this.supremum.subtract(this.infimum)).divide(new BigDecimal(2)));
manager.setRoundMode(oldRoundMode);
return mid;
}
/**
* 区間の半径を求めます。
*
* @return 区間の半径。
*/
private BigDecimal rad() {
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal mid = mid();
BigDecimal rad = mid.subtract(this.infimum);
manager.setRoundMode(oldRoundMode);
return rad;
}
/*public DoubleNumber getError() {
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal ans = this.supremum.subtract(this.infimum);
manager.setRoundMode(oldRoundMode);
return new DoubleNumber(ans);
}*/
/**
* @see org.mklab.cga.interval.scalar.IntervalScalar#printInfSup()
*/
public void printInfSup() {
printInfSup("ans"); //$NON-NLS-1$
}
/**
* @param name input
* @see org.mklab.cga.interval.scalar.IntervalScalar#printInfSup(java.lang.String)
*/
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$
System.out.println();
}
/**
* 自身と実数区間との和を求めます。
*
* @param interval 実数区間
* @return 和。
*/
public BigDecimalIntervalNumber add(final BigDecimalIntervalNumber interval) {// IR+IR
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = this.infimum.add(interval.getInfimum());
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = this.supremum.add(interval.getSupremum());
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* @param d BigDecimalNumber
* @return BigDecimalIntervalNumber
*
*/
public BigDecimalIntervalNumber add(final BigDecimal d) {// IR+R
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = this.infimum.add(d);
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = this.supremum.add(d);
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* 自身と実数区間との差を求めます。
*
* @param interval 実数区間
* @return 差。
*/
public BigDecimalIntervalNumber subtract(final BigDecimalIntervalNumber interval) {// IR-IR
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = this.infimum.subtract(interval.getSupremum());
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = this.supremum.subtract(interval.getInfimum());
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* @param d BigDecimalNumber
* @return BigDecimalIntervalNumber
* @see org.mklab.nfc.scalar.Scalar#subtract(double)
*/
public BigDecimalIntervalNumber subtract(final BigDecimal d) {
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = this.infimum.subtract(d);
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = this.supremum.subtract(d);
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* 自身と実数区間との積を求めます。
*
* @param interval 実数区間
* @return 積
*/
public BigDecimalIntervalNumber multiply(final BigDecimalIntervalNumber interval) {// IR*IR
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
BigDecimal xi = this.infimum;
BigDecimal xs = this.supremum;
BigDecimal yi = interval.getInfimum();
BigDecimal ys = interval.getSupremum();
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = min(xi.multiply(yi), xi.multiply(ys));
inf = min(inf, xs.multiply(yi));
inf = min(inf, xs.multiply(ys));
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = max(xi.multiply(yi), xi.multiply(ys));
sup = max(sup, xs.multiply(yi));
sup = max(sup, xs.multiply(ys));
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* @param d BigDecimalNumber
* @return BigDecimalIntervalNumber
* @see org.mklab.nfc.scalar.Scalar#multiply(double)
*/
public BigDecimalIntervalNumber multiply(final BigDecimal d) {// IR*R
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
BigDecimal xi = this.infimum;
BigDecimal xs = this.supremum;
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = min(xi.multiply(d), xi.multiply(d));
inf = min(inf, xs.multiply(d));
inf = min(inf, xs.multiply(d));
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = max(xi.multiply(d), xi.multiply(d));
sup = max(sup, xs.multiply(d));
sup = max(sup, xs.multiply(d));
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* 自身と実数区間との商を求めます。
*
* @param y 実数区間
* @return 商
*/
public BigDecimalIntervalNumber divide(final BigDecimalIntervalNumber y) {// IR/IR
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
final BigDecimal yi = y.getInfimum();
final BigDecimal ys = y.getSupremum();
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = min(this.infimum .divide(yi), this.infimum.divide(ys));
inf = min(inf, this.supremum.divide(yi));
inf = min(inf, this.supremum.divide(ys));
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = max(this.infimum.divide(yi), this.infimum.divide(ys));
sup = max(sup, this.supremum.divide(yi));
sup = max(sup, this.supremum.divide(ys));
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* 自身と実数区間との商を求めます。
*
* @param y 実数区間
* @param scala 精度
* @return 商
*/
public BigDecimalIntervalNumber divide(final BigDecimalIntervalNumber y, final int scala) {// IR/IR
RoundModeManager manager = RoundModeManager.getManager();
RoundMode oldRoundMode = manager.getRoundMode();
final BigDecimal yi = y.getInfimum();
final BigDecimal ys = y.getSupremum();
manager.setRoundMode(RoundMode.ROUND_DOWN);
BigDecimal inf = min(this.infimum .divide(yi, yi.scale()+scala, RoundingMode.HALF_UP), this.infimum.divide(ys, ys.scale()+scala, RoundingMode.HALF_UP));
inf = min(inf, this.supremum.divide(yi, yi.scale()+scala, RoundingMode.HALF_UP));
inf = min(inf, this.supremum.divide(ys, ys.scale()+scala, RoundingMode.HALF_UP));
manager.setRoundMode(RoundMode.ROUND_UP);
BigDecimal sup = max(this.infimum.divide(yi, yi.scale()+scala, RoundingMode.HALF_UP), this.infimum.divide(ys, ys.scale()+scala, RoundingMode.HALF_UP));
sup = max(sup, this.supremum.divide(yi, yi.scale()+scala, RoundingMode.HALF_UP));
sup = max(sup, this.supremum.divide(ys, ys.scale()+scala, RoundingMode.HALF_UP));
manager.setRoundMode(oldRoundMode);
return new BigDecimalIntervalNumber(inf, sup);
}
/**
* @param a BigDecimalNumber
* @param b BigDecimalNumber
* @return BigDecimal
*/
public static BigDecimal min(BigDecimal a, BigDecimal b) {
return (a.doubleValue() <= b.doubleValue()) ? a : b;
}
/**
* @param a BigDecimalNumber
* @param b BigDecimalNumber
* @return BigDecimal
*/
public static BigDecimal max(BigDecimal a, BigDecimal b) {
return (a.doubleValue() >= b.doubleValue()) ? a : b;
}
/**
* @return BigDecimalNumber
* @see org.mklab.cga.interval.scalar.IntervalScalar#getInfimum()
*/
public BigDecimal getInfimum() {
return this.infimum;
}
/**
* @return BigDecimalNumber
* @see org.mklab.cga.interval.scalar.IntervalScalar#getMiddle()
*/
public BigDecimal getMiddle() {
return this.middle;
}
/**
* @return BigDecimalNumber
*/
public BigDecimal getRadius() {
return this.radius;
}
/**
* @return BigDecimalNumber
* @see org.mklab.cga.interval.scalar.IntervalScalar#getSupremum()
*/
public BigDecimal getSupremum() {
return this.supremum;
}
/**
* @param scalar power
* @return BigDecimalIntervalNumber
*/
public BigDecimalIntervalNumber power(int scalar) {
BigDecimalIntervalNumber value = this.create("1"); //$NON-NLS-1$
if (scalar == 0) {
return value;
}
for (int i = 0; i < scalar; i++) {
value = value.multiply(this);
}
return value;
}
/**
* @param value String
* @return BigDecimalIntervalNumber
*/
public BigDecimalIntervalNumber create(final String value) {
return new BigDecimalIntervalNumber(value);
}
}