xeij/EFPBox.java (2/3)
1 2 3 if (false) {
if ((xd << 1 + xe | xc) != 0L) { //端数がある
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
}
}
return xf >= 0 ? (int) (xd >>> ~xe) : -(int) (xd >>> ~xe);
}
//2^7<=|x|
if (xf >= 0) { //2^7<=x
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
return 0x0000007f;
}
//x<=-2^7
if (xe != 7 || xd != MSB || xc != 0L) { //x!=-2^7
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = M | 0x3fff + xe << 16;
epbExceptionOperandMantissa = this.dvl;
}
return 0xffffff80;
} //efp.getb()
public int getb (int roundingMode) {
return (roundingMode == EPB_MODE_RN ? new EFP ().inner ().rint (this).outer ().getb () :
roundingMode == EPB_MODE_RM ? new EFP ().inner ().floor (this).outer ().getb () :
roundingMode == EPB_MODE_RP ? new EFP ().inner ().ceil (this).outer ().getb () :
new EFP ().inner ().trunc (this).outer ().getb ());
} //efp.getb(int)
//------------------------------------------------------------------------
//d = x.getd ()
//d = x.getd (roundingMode)
//b = x.getd01 (b, a)
//b = x.getd01 (b, a, roundingMode)
//ib = x.getd01 (ib, ia)
//ib = x.getd01 (ib, ia, roundingMode)
//l = x.getd01 ()
//l = x.getd01 (roundingMode)
// double値
//
// 0x7fffffffffffffffL Non-Signaling NaN
// 0x7ff7ffffffffffffL Signaling NaN
// 0x7ff0000000000000L +Inf
// 0x7fefffffffffffffL 2^1024-2^971 = 1.7976931348623157081452742373170435680 E308 正規化数の最大値
// 0x3ff0000000000000L 2^0 = 1
// 0x0010000000000000L 2^-1022 = 2.2250738585072013830902327173324040642 E-308 正規化数の最小値
// 0x000fffffffffffffL 2^-1022-2^-1074 = 2.2250738585072008890245868760858598877 E-308 非正規化数の最大値
// 0x0000000000000001L 2^-1074 = 4.9406564584124654417656879286822137237 E-324 非正規化数の最小値
// 0x0000000000000000L +0
// NaNの符号はDon't Care、出力は0
// Non-Signaling NaNの小数部の先頭は1
// Signaling NaNの小数部の先頭は0
// Signaling NaNが返ることはない
// NaNの小数部の先頭以外はNon-Zero、出力はすべて1
// ±Infの小数部はすべて0
//
// for (long l : new long[] {
// 0x7ff0000000000000L,
// 0x7fefffffffffffffL,
// 0x3ff0000000000000L,
// 0x0010000000000000L,
// 0x000fffffffffffffL,
// 0x0000000000000001L,
// 0x0000000000000000L,
// }) {
// System.out.printf (" // 0x%016x %.17g\n", l, Double.longBitsToDouble (l));
// }
// 0x7ff0000000000000 Infinity
// 0x7fefffffffffffff 1.7976931348623157e+308
// 0x3ff0000000000000 1.0000000000000000
// 0x0010000000000000 2.2250738585072014e-308
// 0x000fffffffffffff 2.2250738585072010e-308
// 0x0000000000000001 4.9000000000000000e-324 不正確なのではなくて非正規化数の有効桁数が調整されている
// 0x0000000000000000 0.0000000000000000
//
// 丸めモードを省略したときは最も近い値に丸める(RN)
//
public final double getd () {
return getd (EPB_MODE_RN);
} //efp.getd()
public final double getd (int roundingMode) {
return Double.longBitsToDouble (getd01 (roundingMode));
} //efp.getd(int)
public final byte[] getd01 (byte[] b, int a) {
return getd01 (b, a, EPB_MODE_RN);
} //efp.getd01(byte[],int)
public final byte[] getd01 (byte[] b, int a, int roundingMode) {
long l = getd01 (roundingMode);
b[a] = (byte) (l >> 56);
b[a + 1] = (byte) (l >> 48);
b[a + 2] = (byte) (l >> 40);
b[a + 3] = (byte) (l >> 32);
b[a + 4] = (byte) (l >> 24);
b[a + 5] = (byte) (l >> 16);
b[a + 6] = (byte) (l >> 8);
b[a + 7] = (byte) l;
return b;
} //efp.getd01(byte[],int,int)
public final int[] getd01 (int[] ib, int ia) {
return getd01 (ib, ia, EPB_MODE_RN);
} //efp.getd01(int[],int)
public final int[] getd01 (int[] ib, int ia, int roundingMode) {
long l = getd01 (roundingMode);
ib[ia] = (int) (l >> 32);
ib[ia + 1] = (int) l;
return ib;
} //efp.getd01(int[],int,int)
public final long getd01 () {
return getd01 (EPB_MODE_RN);
} //efp.getd01()
public final long getd01 (int roundingMode) {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
return (xf << 1 < 0 ? 0 <= xf ? 0x0000000000000000L : 0x8000000000000000L : //±0
xf << 2 < 0 ? 0 <= xf ? 0x7ff0000000000000L : 0xfff0000000000000L : //±Inf
EFP_FPCP_NAN ? 0x7fffffffffffffffL : 0x7ff8000000000000L); //NaN
}
//±0,±Inf,NaN以外
int xe = this.epp; //正規化数は-1022<=xe<=1023、非正規化数は-1075<=xe<=-1023
long xd = this.dvl;
long xc = this.cvl;
if (xe < -1075) { //指数部が小さすぎる。非正規化数の最小値は2^-1074だが丸めで繰り上がる場合があるので一旦2^-1075まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return (0 <= xf ?
roundingMode == EPB_MODE_RP ? 0x0000000000000001L : 0x0000000000000000L : //RPのとき+eps,RN,RZ,RMのとき+0
roundingMode == EPB_MODE_RM ? 0x8000000000000001L : 0x8000000000000000L); //RMのとき-eps,RN,RZ,RPのとき-0
}
if (1023 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if ((xd << 53 | xc) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return (0 <= xf ?
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RM ? 0x7fefffffffffffffL : 0x7ff0000000000000L : //RZ,RMのとき+max,RN,RPのとき+Inf
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RP ? 0xffefffffffffffffL : 0xfff0000000000000L); //RZ,RPのとき-max,RN,RMのとき-Inf
}
long xb = 0L;
int o = xe <= -1023 ? 11 + -1022 - xe : 11; //右にずらすbit数。正規化数は11、非正規化数は11+1<=o<=11+53
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd >>> 53 != 0L) { //繰り上がって溢れたとき
xd = 1L << 52;
xe++; //指数部をインクリメントする。ここでxe=1024になる場合がある
if (1023 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return (0 <= xf ?
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RM ? 0x7fefffffffffffffL : 0x7ff0000000000000L : //RZ,RMのとき+max,RN,RPのとき+Inf
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RP ? 0xffefffffffffffffL : 0xfff0000000000000L); //RZ,RPのとき-max,RN,RMのとき-Inf
} //if 指数部が大きすぎる
} else if (11 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* getd01 */
if (xe == -1022) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 52;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
/**/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -1023) { //非正規化数
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (xd == 0L) { //非正規化数でxe==-1075だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return (0 <= xf ?
roundingMode == EPB_MODE_RP ? 0x0000000000000001L : 0x0000000000000000L : //RPのとき+eps,RN,RZ,RMのとき+0
roundingMode == EPB_MODE_RM ? 0x8000000000000001L : 0x8000000000000000L); //RMのとき-eps,RN,RZ,RPのとき-0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -1023) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (xd == 0L) { //非正規化数でxe==-1075だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return (0 <= xf ?
roundingMode == EPB_MODE_RP ? 0x0000000000000001L : 0x0000000000000000L : //RPのとき+eps,RN,RZ,RMのとき+0
roundingMode == EPB_MODE_RM ? 0x8000000000000001L : 0x8000000000000000L); //RMのとき-eps,RN,RZ,RPのとき-0
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
return ((long) (xf | Math.max (0, xe + 1023) << 52 - 32) << 32 | //符号と指数部
xd & ((1L << 52) - 1L)); //仮数部。正規化数のときは先頭の1を取り除く
} //efp.getd01(int)
//------------------------------------------------------------------------
//x = x.getexp ()
//y = y.getexp (x)
// 指数部
//
// getexp(±0)=±0, getexp(±Inf)=NaN, getexp(NaN)=NaN
//
public final EFP getexp () {
return this.getexp (this);
} //efp.getexp()
public final EFP getexp (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 2 < 0) { //±Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N; //getexp(±Inf)=NaN
} else { //±0,NaN
this.flg = xf; //getexp(±0)=±0, getexp(NaN)=NaN
}
return this;
}
return this.seti (x.epp); //指数部
} //efp.getexp(EFP)
//------------------------------------------------------------------------
//f = x.getf ()
//f = x.getf (roundingMode)
//b = x.getf0 (b, a)
//b = x.getf0 (b, a, roundingMode)
//ib = x.getf0 (ib, a)
//ib = x.getf0 (ib, a, roundingMode)
//i = x.getf0 ()
//i = x.getf0 (roundingMode)
// float値
//
// 0x7fffffff Non-Signaling NaN
// 0x7fbfffff Signaling NaN
// 0x7f800000 +Inf
// 0x7f7fffff 2^128-2^104 = 3.4028234663852885981170418348451692544 E38 正規化数の最大値
// 0x3f800000 2^0 = 1
// 0x00800000 2^-126 = 1.1754943508222875079687365372222456778 E-38 正規化数の最小値
// 0x007fffff 2^-126-2^-149 = 1.1754942106924410754870294448492873488 E-38 非正規化数の最大値
// 0x00000001 2^-149 = 1.4012984643248170709237295832899161313 E-45 非正規化数の最小値
// 0x00000000 +0
// NaNの符号はDon't Care、出力は0
// Non-Signaling NaNの小数部の先頭は1
// Signaling NaNの小数部の先頭は0
// Signaling NaNが返ることはない
// NaNの小数部の先頭以外はNon-Zero、出力はすべて1
// ±Infの小数部はすべて0
//
// for (int i : new int[] {
// 0x7f800000,
// 0x7f7fffff,
// 0x3f800000,
// 0x00800000,
// 0x007fffff,
// 0x00000001,
// 0x00000000,
// }) {
// System.out.printf (" // 0x%08x %.17g\n", i, Float.intBitsToFloat (i));
// }
// 0x7f800000 Infinity
// 0x7f7fffff 3.4028234663852886e+38
// 0x3f800000 1.0000000000000000
// 0x00800000 1.1754943508222875e-38
// 0x007fffff 1.1754942106924411e-38
// 0x00000001 1.4012984643248170e-45 doubleでは正規化数なので有効桁数は17桁
// 0x00000000 0.0000000000000000
//
// 丸めモードを省略したときは最も近い値に丸める(RN)
//
public final float getf () {
return getf (EPB_MODE_RN);
} //efp.getf()
public final float getf (int roundingMode) {
return Float.intBitsToFloat (getf0 (roundingMode));
} //efp.getf(int)
public final byte[] getf0 (byte[] b, int a) {
return getf0 (b, a, EPB_MODE_RN);
} //efp.getf0(byte[],int)
public final byte[] getf0 (byte[] b, int a, int roundingMode) {
int i = getf0 (roundingMode);
b[a] = (byte) (i >> 24);
b[a + 1] = (byte) (i >> 16);
b[a + 2] = (byte) (i >> 8);
b[a + 3] = (byte) i;
return b;
} //efp.getf0(byte[],int,int)
public final int[] getf0 (int[] ib, int ia) {
return getf0 (ib, ia, EPB_MODE_RN);
} //efp.getf0(int[],int)
public final int[] getf0 (int[] ib, int ia, int roundingMode) {
ib[ia] = getf0 (roundingMode);
return ib;
} //efp.getf0(int[],int,int)
public final int getf0 () {
return getf0 (EPB_MODE_RN);
} //efp.getf0()
public final int getf0 (int roundingMode) {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
return (xf << 1 < 0 ? xf & M : //±0
xf << 2 < 0 ? (xf & M) | 0x7f800000 : //±Inf
EFP_FPCP_NAN ? 0x7fffffff : 0x7fc00000); //NaN
}
//±0,±Inf,NaN以外
int xe = this.epp; //正規化数は-126<=xe<=127、非正規化数は-149<=xe<=-127
long xd = this.dvl;
long xc = this.cvl;
if (xe < -150) { //指数部が小さすぎる。非正規化数の最小値は2^-149だが丸めで繰り上がる場合があるので一旦2^-150まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return (0 <= xf ?
roundingMode == EPB_MODE_RP ? 0x00000001 : 0x00000000 : //RPのとき+eps,RN,RZ,RMのとき+0
roundingMode == EPB_MODE_RM ? 0x80000001 : 0x80000000); //RMのとき-eps,RN,RZ,RPのとき-0
}
if (127 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if ((xd << 24 | xc) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return (0 <= xf ?
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RM ? 0x7f7fffff : 0x7f800000 : //RZ,RMのとき+max,RN,RPのとき+Inf
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RP ? 0xff7fffff : 0xff800000); //RZ,RPのとき-max,RN,RMのとき-Inf
}
long xb = 0L;
int o = xe <= -127 ? 40 + -126 - xe : 40; //右にずらすbit数。正規化数は40、非正規化数は40+1<=o<=40+24
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << -1 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd >>> 24 != 0L) { //繰り上がって溢れたとき
xd = 1L << 23;
xe++; //指数部をインクリメントする。ここでxe=128になる場合がある
if (127 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return (0 <= xf ?
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RM ? 0x7f7fffff : 0x7f800000 : //RZ,RMのとき+max,RN,RPのとき+Inf
roundingMode == EPB_MODE_RZ || roundingMode == EPB_MODE_RP ? 0xff7fffff : 0xff800000); //RZ,RPのとき-max,RN,RMのとき-Inf
}
} else if (40 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* getf0 */
if (xe == -126) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 23;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
/**/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -127) { //非正規化数
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (xd == 0L) { //非正規化数でxe==-150だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return (0 <= xf ?
roundingMode == EPB_MODE_RP ? 0x00000001 : 0x00000000 : //RPのとき+eps,RN,RZ,RMのとき+0
roundingMode == EPB_MODE_RM ? 0x80000001 : 0x80000000); //RMのとき-eps,RN,RZ,RPのとき-0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -127) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (xd == 0L) { //非正規化数でxe==-150だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return (0 <= xf ?
roundingMode == EPB_MODE_RP ? 0x00000001 : 0x00000000 : //RPのとき+eps,RN,RZ,RMのとき+0
roundingMode == EPB_MODE_RM ? 0x80000001 : 0x80000000); //RMのとき-eps,RN,RZ,RPのとき-0
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
return (xf | Math.max (0, xe + 127) << 23 | //符号と指数部
(int) xd & ((1 << 23) - 1)); //仮数部。正規化数のときは先頭の1を取り除く
} //efp.getf0(int)
//------------------------------------------------------------------------
//i = x.geti ()
//i = x.geti (roundingMode)
// int値
//
// 丸めモードを省略したときは小数点以下を切り捨てる(RZ)
// 2^31-1よりも大きい数は2^31-1に、-2^31よりも小さい数は-2^31に変換する(飽和変換)
// NaNは-1に変換する
//
public int geti () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
return 0;
} else if (xf << 2 < 0) { //±Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
return xf >> 31 ^ 0x7fffffff; //+Infは0x7fffffff,-Infは0x80000000
} else { //NaN
epbFpsr |= EPB_FPSR_OE | EPB_FPSR_AV;
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xffffffffffffffffL;
return -1; //NaNは-1
}
}
//±0,±Inf,NaN以外
int xe = this.epp;
long xd = this.dvl;
long xc = this.cvl;
if (xe < 0) { //0<|x|<1
if (false) {
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
}
return 0;
}
//1<=|x|
if (xe < 31) { //1<=|x|<2^31
if (false) {
if ((xd << 1 + xe | xc) != 0L) { //端数がある
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
}
}
return xf >= 0 ? (int) (xd >>> ~xe) : -(int) (xd >>> ~xe);
}
//2^31<=|x|
if (xf >= 0) { //2^31<=x
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
return 0x7fffffff;
}
//x<=-2^31
if (xe != 31 || xd != MSB || xc != 0L) { //x!=-2^31
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = M | 0x3fff + xe << 16;
epbExceptionOperandMantissa = this.dvl;
}
return 0x80000000;
} //efp.geti()
public int geti (int roundingMode) {
return (roundingMode == EPB_MODE_RN ? new EFP ().inner ().rint (this).outer ().geti () :
roundingMode == EPB_MODE_RM ? new EFP ().inner ().floor (this).outer ().geti () :
roundingMode == EPB_MODE_RP ? new EFP ().inner ().ceil (this).outer ().geti () :
new EFP ().inner ().trunc (this).outer ().geti ());
} //efp.geti(int)
//------------------------------------------------------------------------
//i = x.geti32 ()
// x&0xffffffff
// 整数部の下位32bit
//
public int geti32 () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
return 0;
}
int t = this.geti32abs ();
return xf < 0 ? -t : t;
} //efp.geti32
//------------------------------------------------------------------------
//i = x.geti32abs ()
// abs(x)&0xffffffff
// 絶対値の整数部の下位32bit
//
public int geti32abs () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
return 0;
}
//±0,±Inf,NaN以外
// -2 | 0.0ddd dddd dccc cccc c000 0000 0
// -1 0 + 0.dddd dddd cccc cccc 0000 0000
// 0 d>>>63 + d.dddd dddc cccc ccc0 0000 000
// 30 | ddd.dddd dccc cccc c000 0000 0
// 31 | dddd.dddd cccc cccc 0000 0000
// 32 | d dddd.dddc cccc ccc0 0000 000
// 62 | ddd dddd.dccc cccc c000 0000 0
// 63 d>>>0 + dddd dddd.cccc cccc 0000 0000
// 64 d<<1|c>>>63 + d dddd dddc.cccc ccc0 0000 000
// 94 d<<31|c>>>33 + ddd dddd dccc.cccc c000 0000 0
// 95 c>>>32 + dddd dddd cccc.cccc 0000 0000
// 96 | d dddd dddc cccc.ccc0 0000 000
// 126 c>>>1 + ddd dddd dccc cccc.c000 0000 0
// 127 dddd dddd cccc cccc.0000 0000 + c<<0
// 128 d dddd dddc cccc ccc0.0000 000 |
// 158 ddd dddd dccc cccc c000.0000 0 + c<<31
// 159 dddd dddd cccc cccc 0000.0000 + 0
// 160 d dddd dddc cccc ccc0 0000.000 |
// 190 ddd dddd dccc cccc c000 0000.0 |
// 191 dddd dddd cccc cccc 0000 0000.0 |
// 192 d dddd dddc cccc ccc0 0000 0000.0 |
// ^^^^
int xe = this.epp;
long xd = this.dvl;
long xc = this.cvl;
return (xe <= -1 ? 0 :
xe <= 63 ? (int) (xd >>> (63 - xe)) :
xe <= 94 ? (int) (xd << (xe - 63) | xc >>> (127 - xe)) :
xe <= 126 ? (int) (xc >>> (127 - xe)) :
xe <= 158 ? (int) (xc << (xe - 127)) :
0);
} //efp.geti32abs
//------------------------------------------------------------------------
//l = x.geti64 ()
// x&0xffffffffffffffffL
// 整数部の下位64bit
//
public long geti64 () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
return 0L;
}
long t = this.geti64abs ();
return xf < 0 ? -t : t;
} //efp.geti64
//------------------------------------------------------------------------
//l = x.geti64abs ()
// abs(x)&0xffffffffffffffffL
// 絶対値の整数部の下位64bit
//
public long geti64abs () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
return 0L;
}
//±0,±Inf,NaN以外
// -2 | 0.0ddd dddd dccc cccc c000 0000 0
// -1 0 + 0.dddd dddd cccc cccc 0000 0000
// 0 d>>>63 + d.dddd dddc cccc ccc0 0000 000
// 30 | ddd.dddd dccc cccc c000 0000 0
// 31 | dddd.dddd cccc cccc 0000 0000
// 32 | d dddd.dddc cccc ccc0 0000 000
// 62 | ddd dddd.dccc cccc c000 0000 0
// 63 d>>>0 + dddd dddd.cccc cccc 0000 0000
// 64 d<<1|c>>>63 + d dddd dddc.cccc ccc0 0000 000
// 94 | ddd dddd dccc.cccc c000 0000 0
// 95 | dddd dddd cccc.cccc 0000 0000
// 96 | d dddd dddc cccc.ccc0 0000 000
// 126 d<<63|c>>>1 + ddd dddd dccc cccc.c000 0000 0
// 127 dddd dddd cccc cccc.0000 0000 + c<<0
// 128 d dddd dddc cccc ccc0.0000 000 |
// 158 ddd dddd dccc cccc c000.0000 0 |
// 159 dddd dddd cccc cccc 0000.0000 |
// 160 d dddd dddc cccc ccc0 0000.000 |
// 190 ddd dddd dccc cccc c000 0000.0 + c<<63
// 191 dddd dddd cccc cccc 0000 0000.0 + 0
// 192 d dddd dddc cccc ccc0 0000 0000.0 |
// ^^^^ ^^^^
int xe = this.epp;
long xd = this.dvl;
long xc = this.cvl;
return (xe <= -1 ? 0L :
xe <= 63 ? (xd >>> (63 - xe)) :
xe <= 126 ? (xd << (xe - 63) | xc >>> (127 - xe)) :
xe <= 190 ? (xc << (xe - 127)) :
0L);
} //efp.geti64abs
//------------------------------------------------------------------------
//l = x.getl ()
// long値
//
// 丸めモードを省略したときは小数点以下を切り捨てる(RZ)
// 2^63-1よりも大きい数は2^63-1に、-2^63よりも小さい数は-2^63に変換する(飽和変換)
// NaNは0に変換する
//
public long getl () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
return 0L;
} else if (xf << 2 < 0) { //±Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
return xf < 0 ? MSB : ~MSB; //+Infは0x7fffffffffffffffL,-Infは0x8000000000000000L
} else { //NaN
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xffffffffffffffffL;
return 0L; //NaNは0L
}
}
//±0,±Inf,NaN以外
int xe = this.epp;
if (xe < 0) { //0<|x|<1
return 0L;
}
//1<=|x|
if (xe < 63) { //1<=|x|<2^63
return xf >= 0 ? this.dvl >>> ~xe : -(this.dvl >>> ~xe);
}
//2^63<=|x|
if (xf >= 0) { //2^63<=x
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = 0x3fff + xe << 16;
epbExceptionOperandMantissa = this.dvl;
return 0x7fffffffffffffffL;
}
//x<=-2^63
if (xe != 63 || this.dvl != MSB || this.cvl != 0L) { //x!=-2^63
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = M | 0x3fff + xe << 16;
epbExceptionOperandMantissa = this.dvl;
}
return 0x8000000000000000L;
} //efp.getl()
public long getl (int roundingMode) {
return (roundingMode == EPB_MODE_RN ? new EFP ().inner ().rint (this).outer ().getl () :
roundingMode == EPB_MODE_RM ? new EFP ().inner ().floor (this).outer ().getl () :
roundingMode == EPB_MODE_RP ? new EFP ().inner ().ceil (this).outer ().getl () :
this.getl ());
} //efp.getl(int)
//------------------------------------------------------------------------
//x = x.getman ()
//y = y.getman (x)
// 仮数部
//
// getman(±0)=±0, getman(±Inf)=NaN, getman(NaN)=NaN
//
public final EFP getman () {
return this.getman (this);
} //efp.getman()
public final EFP getman (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 2 < 0) { //±Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N; //getman(±Inf)=NaN
} else { //±0,NaN
this.flg = xf; //getman(±0)=±0, getman(NaN)=NaN
}
return this;
}
this.flg = xf; //仮数部
this.epp = 0;
this.dvl = x.dvl;
this.cvl = x.cvl;
return this;
} //efp.getman(EFP)
//------------------------------------------------------------------------
//b = x.getp012 (b, a)
//b = x.getp012 (b, a, k)
//ib = x.getp012 (ib, ia)
//ib = x.getp012 (ib, ia, k)
// packed値
//
// 0
// bit31 仮数部の符号(0=+,1=-)
// bit30 指数部の符号(0=+,1=-)
// bit29-28 ±Inf,NaNのときはすべて1、それ以外はすべて0
// bit27-16 指数部(BCD)、±0のときはすべて0、±Inf,NaNのときはすべて1
// bit15-12 出力するときは指数部の1000の位、入力するときは不定。±Infのときはすべて0にしておかないとFLOAT4.Xが誤動作する
// bit11-4 不定。±Infのときはすべて0にしておかないとFLOAT4.Xが誤動作する
// bit3-0 整数部(BCD)、±0,±Infのときはすべて0、NaNのときはすべて1
// 12
// bit63-0 小数部(BCD)、±0,±Infのときはすべて0、NaNのときはすべて1、ただしSNaNのときはbit63だけ0
//
// k-factor
// -64..0 -小数点以下の桁数(%f)。0ではない先頭の数字から小数点以下-k桁目までの桁数(1桁以上17桁以下)を有効桁数とする
// 1..17 有効桁数(%e)
// 18..63 OPERR
//
public byte[] getp012 (byte[] b, int a) {
return getp012 (b, a, 17);
} //efp.getp012(byte[],int)
public byte[] getp012 (byte[] b, int a, int k) {
int[] ib = getp012 (new int[3], 0, k);
int i = ib[0];
b[a] = (byte) (i >> 24);
b[a + 1] = (byte) (i >> 16);
b[a + 2] = (byte) (i >> 8);
b[a + 3] = (byte) i;
i = ib[1];
b[a + 4] = (byte) (i >> 24);
b[a + 5] = (byte) (i >> 16);
b[a + 6] = (byte) (i >> 8);
b[a + 7] = (byte) i;
i = ib[2];
b[a + 8] = (byte) (i >> 24);
b[a + 9] = (byte) (i >> 16);
b[a + 10] = (byte) (i >> 8);
b[a + 11] = (byte) i;
return b;
} //efp.getp012(byte[],int,int)
public int[] getp012 (int[] ib, int ia) {
return getp012 (ib, ia, 17);
} //efp.getp012(int[],int)
public int[] getp012 (int[] ib, int ia, int k) {
k = k << -7 >> -7; //下位7bitを符号拡張する
int u;
long v;
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
u = xf & M;
v = 0L;
} else if (xf << 2 < 0) { //±Inf
u = (xf & M) | 0x7fff0000;
v = 0L;
} else { //NaN
u = 0x7fff0000;
v = 0xffffffffffffffffL;
}
} else { //±0,±Inf,NaN以外
if (k > 17) {
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = this.flg & M | 0x3fff + this.epp << 16;
epbExceptionOperandMantissa = this.dvl;
k = 17;
}
// 2進数で仮数部が64桁のextendedは2^n*5^27を正確に表現できる
// 10進数で仮数部が17桁のpackedは2^56*10^nを正確に表現できる
// どちらも正確に表現できる2^56*10^27=2^83*5^27のextendedとpackedの相互変換は誤差なしで行われなければならない
// 2^56*10^27=72057594037927936000000000000000000000000000(44桁)
// extended 40900000CECB8F27F4200F3A
// packed 004300072057594037927936
// 同様に2^56*10^34=2^90*5^34のtripleとpackedの相互変換は誤差なしで行われなければならない
// 2^56*10^34=720575940379279360000000000000000000000000000000000(51桁)
// triple 40A7C732F684DF56C3E01BC6
// packed 005000072057594037927936
int xe = this.epp;
long xd = this.dvl;
long xc = this.cvl;
EFP x = new EFP (P, xe, xd, xc); //絶対値のコピー
int savedFpsr = epbFpsr;
this.inner ();
//10の指数を決める
// 1.0*2^xe <= x < 2.0*2^xe
// 1.0*10^(log10(2)*xe) <= x < 2.0*10^(log10(2)*xe)
// e=floor(log10(2)*xe)
// 1.0*10^e <= x < 2.0*10^(e+1)
// 1.0*10^e <= x < 20.0*10^e
int e = (int) Math.floor (0.30102999566398119521373889472449302677 * xe);
//整数部を0桁から20桁にする
// 常に1桁まで割ってしまうとpackedで表現できる整数の処理中に端数が生じてX2がセットされてしまう
if (e < 0) { //10^-eを掛ける。結果は10^0<=x<2*10^1で整数部が1桁または2桁になる。誤差で0桁になる場合がある
int o = -e;
EFP t = new EFP (ONE);
for (int i = 0; o != 0; i++, o >>>= 1) {
if ((o & 1) != 0) {
t.imul (EFP_TEN_POWER_P[i]);
}
}
x.imul (t);
} else if (e <= 18) { //そのまま。10^0<=x<20*10^18で整数部は1桁から20桁
e = 0;
} else { //10^(e-18)で割る。結果は10^18<=x<20*10^18で整数部が19桁または20桁になる。誤差で18桁になる場合がある
int o = e -= 18;
EFP t = new EFP (ONE);
for (int i = 0; o != 0; i++, o >>>= 1) {
if ((o & 1) != 0) {
t.imul (EFP_TEN_POWER_P[i]);
}
}
x.div (t);
}
//整数部を展開する
// 最大65bitの整数を10000で割って16桁の商と4桁の余りに分けてそれぞれBCDに変換する
// 20^10^18-1=0x1158E460913CFFFFF(65bit)
u = 0;
v = 0L;
if (0 <= x.epp) { //整数部が1..65bit
//整数部をs,tに取り出す
long s, t;
if (x.epp <= 63) { //1..64bit
s = 0L;
t = x.dvl >>> ~x.epp;
} else { //65bit
s = 1L; //最上位は1
t = x.dvl << 1 | x.cvl >>> -1;
}
//最大65bitの整数を10000で割る
long r = s << 32 | t >>> 32; //上位の被除数
s = r / 10000L; //上位の商
r = r - s * 10000L << 32 | t & 0xffffffffL; //下位の被除数
t = r / 10000L; //下位の商
v = XEiJ.FMT_BCD4[(int) (r - t * 10000L)]; //下位の余り→下位4桁
t = XEiJ.fmtBcd16 (s << 32 | t); //全体の商→上位16桁
u = (int) (t >>> 48);
v |= t << 16;
}
//小数部を展開する
// 整数部が18桁以上になるまで小数部を10000倍して整数部を4桁のBCDに変換することを繰り返す
while ((u & 0xfffffff0) == 0) {
u = u << 16 | (int) (v >>> -16);
v = v << 16 | XEiJ.FMT_BCD4[x.frac ().muli (10000).geti32abs ()];
e -= 4;
}
long rest = x.frac ().iszero () ? 0L : 1L; //k+2桁目以降の端数の有無
this.outer ();
epbFpsr = savedFpsr;
//四捨五入する位を確認する
// lz(u) >>>2 24-
// 12..15 3 21
// 16..19 4 20
// 20..23 5 19
// 24..27 6 18
int w = 24 - (Integer.numberOfLeadingZeros (u) >>> 2); //展開された桁数。18桁以上21桁以下
// w桁のBCD値がu:vの96bitに右寄せで格納されている
// 値はw桁のBCD値*10^e
if (k <= 0) { //固定小数点形式のとき
// 先頭の数字の左側は右からw桁の位置
// 小数点は右から-e桁の位置
// 小数点以下-k桁の数字の右側は右から-e+k桁の位置
// 先頭から小数点以下-k桁までの桁数はw-(-e+k)桁
k = Math.max (1, Math.min (17, w + e - k));
}
//k+2桁目以降の端数の有無を確認する
int i = w - k - 1 << 2; //k+1桁目の右から数えたbit位置
if (0 < i) { //k+2桁目が展開されている
if (i < 64) { //k+1桁目がvにある。k+2桁目以降はvの右端からvの途中まで
long mask = -1L << i;
rest |= v & ~mask; //k+2桁目以降の端数の有無
v &= mask;
} else { //k+1桁目がuにある。k+2桁目以降はvの全体のみまたはvの全体とuの右端から途中まで
int mask = -1 << i - 64;
rest |= (long) (u & ~mask) | v; //k+2桁目以降の端数の有無
u &= mask;
v = 0L;
}
}
//k+1桁目を四捨五入する
int d = (i < 64 ? (int) (v >>> i) : u >>> i - 64) & 15; //k+1桁目の数字
if (d != 0 || rest != 0L) { //k+1桁目以降に端数がある
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = xf & M | 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
if (i < 64) {
v &= ~(15L << i);
} else {
u &= ~(15 << i);
}
i += 4; //k桁目の右から数えたbit位置
if ((epbRoundingMode == EPB_MODE_RN &&
(5 < d || //k+1桁目以降に端数があってRNでk+1桁目が5より大きいか、
(d == 5 && (rest != 0L || //k+1桁目が5でk+2桁目以降に端数があるか、
((i < 64 ? (int) (v >>> i) : u >>> i - 64) & 1) != 0)))) || //k+1桁目が5でk+2桁目以降に端数がなくてk桁目が奇数または
(epbRoundingMode == EPB_MODE_RM && xf < 0) || //k+1桁目以降に端数があってRMで負または
(epbRoundingMode == EPB_MODE_RP && 0 <= xf)) { //k+1桁目以降に端数があってRPで正のとき切り上げる
//k桁目が9のとき0に変えて切り上げる
// 切り上げたときk-1桁目が9のとき0に変えて切り上げる
// 先頭に0があるので必ず止まる
while (((i < 64 ? (int) (v >>> i) : u >>> i - 64) & 15) == 9) {
if (i < 64) {
v &= ~(15L << i);
} else {
u &= ~(15 << i);
}
i += 4;
}
//9でなければ1を加える
// 先頭の0が1に変わって1桁増える場合がある
if (i < 64) {
v += 1L << i;
} else {
u += 1 << i;
}
} //切り上げる
} //if 端数がある
//小数点の位置を合わせる
w = 7 - (Integer.numberOfLeadingZeros (u) >>> 2); //四捨五入した後の多すぎる小数点以下の桁数
e += 16 + w;
i = w << 2; //多すぎるbit数
v = (long) u << -i | v >>> i;
u >>>= i - 64;
//指数部を展開する
if (e < 0) {
u |= 0x40000000; //指数部の符号
e = -e;
}
e = XEiJ.fmtBcd8 (e);
if ((e & ~0xfff) != 0) { //指数部が3桁に収まっていない
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
}
u |= (e & 0xfff) << 16 | (e & 0xf000);
//符号を付ける
u |= xf & M; //仮数部の符号
}
ib[ia] = u;
ib[ia + 1] = (int) (v >> 32);
ib[ia + 2] = (int) v;
return ib;
} //efp.getp012(int[],int,int)
//------------------------------------------------------------------------
//i = x.gets ()
//i = x.gets (roundingMode)
// short値
//
// 丸めモードを省略したときは小数点以下を切り捨てる(RZ)
// 2^15-1よりも大きい数は2^15-1に、-2^15よりも小さい数は-2^15に変換する(飽和変換)
// NaNは-1に変換する
//
// Javaのdoubleからshortへのキャストは飽和変換ではない(intに飽和変換してから下位16bitを取り出す)ことに注意
//
public int gets () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
return 0;
} else if (xf << 2 < 0) { //±Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
return xf >> 31 ^ 0x00007fff; //+Infは0x00007fff,-Infは0xffff8000
} else { //NaN
epbFpsr |= EPB_FPSR_OE | EPB_FPSR_AV;
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xffffffffffffffffL;
return -1; //NaNは-1
}
}
//±0,±Inf,NaN以外
int xe = this.epp;
long xd = this.dvl;
long xc = this.cvl;
if (xe < 0) { //0<|x|<1
if (false) {
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
}
return 0;
}
//1<=|x|
if (xe < 15) { //1<=|x|<2^15
if (false) {
if ((xd << 1 + xe | xc) != 0L) { //端数がある
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
}
}
return xf >= 0 ? (int) (xd >>> ~xe) : -(int) (xd >>> ~xe);
}
//2^15<=|x|
if (xf >= 0) { //2^15<=x
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = 0x3fff + xe << 16;
epbExceptionOperandMantissa = xd;
return 0x00007fff;
}
//x<=-2^15
if (xe != 15 || xd != MSB || xc != 0L) { //x!=-2^15
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = M | 0x3fff + xe << 16;
epbExceptionOperandMantissa = this.dvl;
}
return 0xffff8000;
} //efp.gets()
public int gets (int roundingMode) {
return (roundingMode == EPB_MODE_RN ? new EFP ().inner ().rint (this).outer ().gets () :
roundingMode == EPB_MODE_RM ? new EFP ().inner ().floor (this).outer ().gets () :
roundingMode == EPB_MODE_RP ? new EFP ().inner ().ceil (this).outer ().gets () :
new EFP ().inner ().trunc (this).outer ().gets ());
} //efp.gets(int)
//------------------------------------------------------------------------
//i = x.getx0 ()
//i = x.getx0 (roundingMode)
//l = x.getx12 ()
//l = x.getx12 (roundingMode)
//b = x.getx012 (b, a)
//b = x.getx012 (b, a, roundingMode)
//ib = x.getx012 (ib, ia)
//ib = x.getx012 (ib, ia, roundingMode)
// extended値
//
// 0 1 2
// 0x7fff0000,0xffffffffffffffffL Non-Signaling NaN
// 0x7fff0000,0xbfffffffffffffffL Signaling NaN
// 0x7fff0000,0x0000000000000000L +Inf
// 0x7ffe0000,0xffffffffffffffffL 2^16384-2^16320 = 1.1897314953572317650212638530309702052 E4932 正規化数の最大値
// 0x3fff0000,0x8000000000000000L 2^0 = 1
// 0x00000000,0x8000000000000000L 2^-16383 = 1.6810515715560467531313389086608763013 E-4932 正規化数の最小値
// 0x00000000,0x7fffffffffffffffL 2^-16383-2^-16446 = 1.6810515715560467529490789320667525712 E-4932 非正規化数の最大値
// 0x00000000,0x0000000000000001L 2^-16446 = 1.8225997659412373012642029668097099082 E-4951 非正規化数の最小値
// 0x00000000,0x0000000000000000L +0
// NaNの符号はDon't Care、出力は0
// NaNの整数部はDon't Care、出力は1
// Non-Signaling NaNの小数部の先頭は1
// Signaling NaNの小数部の先頭は0
// Signaling NaNが返ることはない
// NaNの小数部の先頭以外はNon-Zero、出力はすべて1
// ±Infの整数部はDon't Care、出力は0
// ±Infの小数部はすべて0
// 正規化数の整数部は1
// 非正規化数の整数部は0
//
// メモ
// M68000PRMとMC68881UMにはextendedの正規化数の最大値と正規化数の最小値と非正規化数の最小値の記述が間違っているものがある
//
public final int getx0 () {
int[] ib = getx012 (new int[3], 0, EPB_MODE_RN);
return ib[0];
} //efp.getx0()
public final int getx0 (int roundingMode) {
int[] ib = getx012 (new int[3], 0, roundingMode);
return ib[0];
} //efp.getx0(int)
public final long getx12 () {
int[] ib = getx012 (new int[3], 0, EPB_MODE_RN);
return (long) ib[1] << 32 | (0xffffffffL & ib[2]);
} //efp.getx12()
public final long getx12 (int roundingMode) {
int[] ib = getx012 (new int[3], 0, roundingMode);
return (long) ib[1] << 32 | (0xffffffffL & ib[2]);
} //efp.getx12(int)
public final byte[] getx012 (byte[] b, int a) {
return getx012 (b, a, EPB_MODE_RN);
} //efp.getx012(byte[],int)
public final byte[] getx012 (byte[] b, int a, int roundingMode) {
int[] ib = getx012 (new int[3], 0, roundingMode);
int i = ib[0];
b[a] = (byte) (i >> 24);
b[a + 1] = (byte) (i >> 16);
b[a + 2] = (byte) (i >> 8);
b[a + 3] = (byte) i;
i = ib[1];
b[a + 4] = (byte) (i >> 24);
b[a + 5] = (byte) (i >> 16);
b[a + 6] = (byte) (i >> 8);
b[a + 7] = (byte) i;
i = ib[2];
b[a + 8] = (byte) (i >> 24);
b[a + 9] = (byte) (i >> 16);
b[a + 10] = (byte) (i >> 8);
b[a + 11] = (byte) i;
return b;
} //efp.getx012(byte[],int,int)
public final int[] getx012 (int[] ib, int ia) {
return this.getx012 (ib, ia, EPB_MODE_RN);
} //efp.getx012(int[],int)
public final int[] getx012 (int[] ib, int ia, int roundingMode) {
int xf = this.flg;
int xe = this.epp; //正規化数は-16383<=xe<=16383、非正規化数は-16446<=xe<=-16384
long xd = this.dvl;
long xc = this.cvl;
xfxd:
{
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
xf &= M; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
} else if (xf << 2 < 0) { //±Inf
xf = (xf & M) | 0x7fff0000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
} else { //NaN
xf = 0x7fff0000; //符号部1bit、指数部15bit、空き16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部63bit
}
break xfxd;
}
//±0,±Inf,NaN以外
if (xe < -16447) { //指数部が小さすぎる。非正規化数の最小値は2^-16446だが丸めで繰り上がる場合があるので一旦2^-16447まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RP) { //RPのとき+eps
xf = 0x00000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000001L; //整数部1bit、小数部63bit
} else { //RN,RZ,RMのとき+0
xf = 0x00000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RM) { //RMのとき-eps
xf = 0x80000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000001L; //整数部1bit、小数部63bit
} else { //RN,RZ,RPのとき-0
xf = 0x80000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
}
break xfxd;
}
if (16383 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if (xc != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RM) { //RMのとき+max
xf = 0x7ffe0000; //符号部1bit、指数部15bit、空き16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部63bit
} else { //RN,RZ,RPのとき+Inf
xf = 0x7fff0000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RP) { //RPのとき-max
xf = 0xfffe0000; //符号部1bit、指数部15bit、空き16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部63bit
} else { //RN,RZ,RMのとき-Inf
xf = 0xffff0000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
}
break xfxd;
}
long xb = 0L;
int o = xe <= -16384 ? 0 + -16383 - xe : 0; //右にずらすbit数。正規化数は0、非正規化数は0+1<=o<=0+64
if (o == 0) {
} else if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd == 0L) { //繰り上がって溢れたとき
xd = MSB;
xe++; //指数部をインクリメントする。ここでxe=16384になる場合がある
if (16383 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RM) { //RMのとき+max
xf = 0x7ffe0000; //符号部1bit、指数部15bit、空き16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部63bit
} else { //RN,RZ,RPのとき+Inf
xf = 0x7fff0000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RP) { //RPのとき-max
xf = 0xfffe0000; //符号部1bit、指数部15bit、空き16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部63bit
} else { //RN,RZ,RMのとき-Inf
xf = 0xffff0000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
}
break xfxd;
} //if 指数部が大きすぎる
} else if (0 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* getx012
if (xe == -16383) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 15;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
*/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (xd == 0L) { //非正規化数でxe==-16447だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RP) { //RPのとき+eps
xf = 0x00000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000001L; //整数部1bit、小数部63bit
} else { //RN,RZ,RMのとき+0
xf = 0x00000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RM) { //RMのとき-eps
xf = 0x80000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000001L; //整数部1bit、小数部63bit
} else { //RN,RZ,RPのとき-0
xf = 0x80000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
}
break xfxd;
}
} //if 非正規化数
} else { //端数が0
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (xd == 0L) { //非正規化数でxe==-16447だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RP) { //RPのとき+eps
xf = 0x00000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000001L; //整数部1bit、小数部63bit
} else { //RN,RZ,RMのとき+0
xf = 0x00000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RM) { //RMのとき-eps
xf = 0x80000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000001L; //整数部1bit、小数部63bit
} else { //RN,RZ,RPのとき-0
xf = 0x80000000; //符号部1bit、指数部15bit、空き16bit
xd = 0x0000000000000000L; //整数部1bit、小数部63bit
}
}
break xfxd;
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
xf |= Math.max (0, 16383 + xe) << 16; //符号とバイアスを加えた指数部
} //xfxd
//結果
ib[ia] = xf;
ib[ia + 1] = (int) (xd >> 32);
ib[ia + 2] = (int) xd;
return ib;
} //efp.getx012(int[],int,int)
//------------------------------------------------------------------------
//i = x.gety0 ()
//i = x.gety0 (roundingMode)
//l = x.gety12 ()
//l = x.gety12 (roundingMode)
//b = x.gety012 (b, a)
//b = x.gety012 (b, a, roundingMode)
//ib = x.gety012 (ib, ia)
//ib = x.gety012 (ib, ia, roundingMode)
// triple値
//
// 0 1 2
// 0x7fffffff,0xffffffffffffffffL Non-Signaling NaN
// 0x7fffffff,0xbfffffffffffffffL Signaling NaN
// 0x7fff0000,0x0000000000000000L +Inf
// 0x7ffeffff,0xffffffffffffffffL 2^16384-2^16304 = 1.1897314953572317650857583425051800275 E4932 正規化数の最大値
// 0x3fff0000,0x8000000000000000L 2^0 = 1
// 0x00000000,0x8000000000000000L 2^-16383 = 1.6810515715560467531313389086608763013 E-4932 正規化数の最小値
// 0x0000ffff,0x7fffffffffffffffL 2^-16383-2^-16462 = 1.6810515715560467531313361275943389154 E-4932 非正規化数の最大値
// 0x00000001,0x0000000000000000L 2^-16462 = 2.7810665373859211750247237652736052066 E-4956 非正規化数の最小値
// 0x00000000,0x0000000000000000L +0
// NaNの符号はDon't Care、出力は0
// NaNの整数部はDon't Care、出力は1
// Non-Signaling NaNの小数部の先頭は1
// Signaling NaNの小数部の先頭は0
// Signaling NaNが返ることはない
// NaNの小数部の先頭以外はNon-Zero、出力はすべて1
// ±Infの整数部はDon't Care、出力は0
// ±Infの小数部はすべて0
// 正規化数の整数部は1
// 非正規化数の整数部は0
//
public final int gety0 () {
int[] ib = gety012 (new int[3], 0, EPB_MODE_RN);
return ib[0];
} //efp.gety0()
public final int gety0 (int roundingMode) {
int[] ib = gety012 (new int[3], 0, roundingMode);
return ib[0];
} //efp.gety0(int)
public final long gety12 () {
int[] ib = gety012 (new int[3], 0, EPB_MODE_RN);
return (long) ib[1] << 32 | (0xffffffffL & ib[2]);
} //efp.gety12()
public final long gety12 (int roundingMode) {
int[] ib = gety012 (new int[3], 0, roundingMode);
return (long) ib[1] << 32 | (0xffffffffL & ib[2]);
} //efp.gety12(int)
public final byte[] gety012 (byte[] b, int a) {
return gety012 (b, a, EPB_MODE_RN);
} //efp.gety012(byte[],int)
public final byte[] gety012 (byte[] b, int a, int roundingMode) {
int[] ib = gety012 (new int[3], 0, roundingMode);
int i = ib[0];
b[a] = (byte) (i >> 24);
b[a + 1] = (byte) (i >> 16);
b[a + 2] = (byte) (i >> 8);
b[a + 3] = (byte) i;
i = ib[1];
b[a + 4] = (byte) (i >> 24);
b[a + 5] = (byte) (i >> 16);
b[a + 6] = (byte) (i >> 8);
b[a + 7] = (byte) i;
i = ib[2];
b[a + 8] = (byte) (i >> 24);
b[a + 9] = (byte) (i >> 16);
b[a + 10] = (byte) (i >> 8);
b[a + 11] = (byte) i;
return b;
} //efp.gety012(byte[],int,int)
public final int[] gety012 (int[] ib, int ia) {
return this.gety012 (ib, ia, EPB_MODE_RN);
} //efp.gety012(int[],int)
public final int[] gety012 (int[] ib, int ia, int roundingMode) {
int xf = this.flg;
int xe = this.epp; //正規化数は-16383<=xe<=16383、非正規化数は-16462<=xe<=-16384
long xd = this.dvl;
long xc = this.cvl;
xfxd:
{
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
xf &= M; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else if (xf << 2 < 0) { //±Inf
xf = (xf & M) | 0x7fff0000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else { //NaN
xf = 0x7fffffff; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部の上位63bit
}
break xfxd;
}
//±0,±Inf,NaN以外
if (xe < -16463) { //指数部が小さすぎる。非正規化数の最小値は2^-16462だが丸めで繰り上がる場合があるので一旦2^-16463まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RP) { //RPのとき+eps
xf = 0x00000001; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RMのとき+0
xf = 0x00000000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RM) { //RMのとき-eps
xf = 0x80000001; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RPのとき-0
xf = 0x80000000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
}
break xfxd;
}
if (16383 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if (xc << 16 != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RM) { //RMのとき+max
xf = 0x7ffeffff; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RPのとき+Inf
xf = 0x7fff0000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RP) { //RPのとき-max
xf = 0xfffeffff; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RMのとき-Inf
xf = 0xffff0000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
}
break xfxd;
}
long xb = 0L;
long xa = 0L;
int o = xe <= -16384 ? 48 + -16383 - xe : 48; //右にずらすbit数。正規化数は48、非正規化数は48+1<=o<=48+80
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else if (o == 64) {
xb = xc;
xc = xd;
xd = 0L;
} else if (o < 128) {
xa = xc << -o;
xb = xd << -o | xc >>> o;
xc = xd >>> o;
xd = 0L;
} else {
xa = xc;
xb = xd;
xc = 0L;
xd = 0L;
}
if ((xb | xa) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
if (roundingMode == EPB_MODE_RN && xb < 0L && (xc << 63 | xb << 1 | xa) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xc++; //繰り上げる
if (xc == 0L) { //繰り上がって溢れたとき
xd++; //繰り上げる
if (xd >>> 16 != 0L) { //繰り上がって溢れたとき
//xd = 1L << 15;
xe++; //指数部をインクリメントする。ここでxe=16384になる場合がある
if (16383 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RM) { //RMのとき+max
xf = 0x7ffeffff; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RPのとき+Inf
xf = 0x7fff0000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RP) { //RPのとき-max
xf = 0xfffeffff; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0xffffffffffffffffL; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RMのとき-Inf
xf = 0xffff0000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
}
break xfxd;
} //if 指数部が大きすぎる
} else if (48 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* gety012
if (xe == -16383) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 15;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
*/
}
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if ((xd | xc) == 0L) { //非正規化数でxe==-16463だったとき、先頭の1がxbにあって丸めで繰り上がらなかった
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RP) { //RPのとき+eps
xf = 0x00000001; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RMのとき+0
xf = 0x00000000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RM) { //RMのとき-eps
xf = 0x80000001; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RPのとき-0
xf = 0x80000000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
}
break xfxd;
}
} //if 非正規化数
} else { //端数が0
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
if ((xd | xc) == 0L) { //非正規化数でxe==-16463だったとき、先頭の1がxbにあって丸めで繰り上がらなかった
if (0 <= xf) { //+x
if (roundingMode == EPB_MODE_RP) { //RPのとき+eps
xf = 0x00000001; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RMのとき+0
xf = 0x00000000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
} else { //-x
if (roundingMode == EPB_MODE_RM) { //RMのとき-eps
xf = 0x80000001; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
} else { //RN,RZ,RPのとき-0
xf = 0x80000000; //符号部1bit、指数部15bit、小数部の下位16bit
xd = 0x0000000000000000L; //整数部1bit、小数部の上位63bit
}
}
break xfxd;
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
xd = xd << 48 | xc >>> -48;
xc <<= 48;
xf |= Math.max (0, 16383 + xe) << 16; //符号とバイアスを加えた指数部
} //xfxd
//結果
ib[ia] = xf | (int) (xc >> 48);
ib[ia + 1] = (int) (xd >> 32);
ib[ia + 2] = (int) xd;
return ib;
} //efp.gety012(byte[],int,int)
//------------------------------------------------------------------------
//b = x.gt (y)
// b=x>y
// より大きいか
//
// -Inf==-Inf<-x<-0==+0<+x<+Inf==+Inf
//
// NaNの扱い
// どちらかがNaNのときはfalseを返す
//
public boolean gt (EFP y) {
int xf = this.flg;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
return EFP_GT_TABLE[xf >>> 28] << (yf >>> 28 - 1) < 0;
}
//両方±0,±Inf,NaN以外
if (xf != yf) { //両方±0,±Inf,NaN以外で符号が違う
return xf > yf;
}
//両方±0,±Inf,NaN以外で符号が同じ
int s;
long t;
return (xf >= 0 ? 1 : -1) * ((s = this.epp - y.epp) != 0 ? s >= 0 ? 1 : -1 :
(t = this.dvl - y.dvl) != 0L ? t >= 0L ? 1 : -1 :
(t = (this.cvl >>> 1) - (y.cvl >>> 1)) != 0L ? t >= 0L ? 1 : -1 :
0) > 0;
} //efp.gt(EFP)
//------------------------------------------------------------------------
//i = x.hashCode ()
// ハッシュコード
//
// equalsであるオブジェクトはhashCodeが同じでなければならない
// equalsでないオブジェクトはhashCodeがなるべく違う方がよい
//
public int hashCode () {
return (this.flg ^
this.epp ^
(int) (this.dvl >> 32) ^
(int) this.dvl ^
(int) (this.cvl >> 32));
} //efp.hashCode()
//------------------------------------------------------------------------
//x = x.ieeerem (y)
// x=IEEEremainder(x,y)
//z = z.ieeerem (x, y)
// z=IEEEremainder(x,y)
// 剰余(round-to-nearest)
//
// JavaのMath.IEEEremainder(x,y)と同じ
// IEEEremainder(x,y)=isNaN(x)||isNaN(y)||isInfinite(x)?NaN:isInfinite(y)?x:x-rint(x/y)*y
// 被除数から最も近い除数の倍数を引いた結果を返す
// 倍数の符号は任意なので除数の符号は結果に影響しない
// IEEEremainder ( 5.0, 3.0) == 5.0 - rint ( 5.0 / 3.0) * 3.0 == -1.0
// IEEEremainder ( 5.0, -3.0) == 5.0 - rint ( 5.0 / -3.0) * -3.0 == -1.0
// IEEEremainder (-5.0, 3.0) == -5.0 - rint (-5.0 / 3.0) * 3.0 == 1.0
// IEEEremainder (-5.0, -3.0) == -5.0 - rint (-5.0 / -3.0) * -3.0 == 1.0
//
public final EFP ieeerem (EFP y) {
return this.ieeerem (this, y);
} //efp.ieeerem(EFP)
public final EFP ieeerem (EFP x, EFP y) {
int xf = x.flg;
int yf = y.flg;
epbFpsr &= 0xff00ffff; //quotient byteをクリアする
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf | yf) << 3 < 0) { //ieeerem(NaN,y)=NaN, ieeerem(x,NaN)=NaN
this.flg = N;
} else if (xf << 2 < 0 || //ieeerem(±Inf,y)=NaN
yf << 1 < 0) { //ieeerem(x,±0)=NaN
//除数が±0でもゼロ除算にはならない
epbFpsr |= EPB_FPSR_OE;
if (yf << 1 < 0) { //±0
epbExceptionOperandExponent = yf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else if (yf << 2 < 0) { //±Inf
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //±y
epbExceptionOperandExponent = yf & M | 0x3fff + y.epp << 16;
epbExceptionOperandMantissa = y.dvl;
}
this.flg = N;
} else if (xf << 1 < 0) { //ieeerem(±0,y)=±0
epbFpsr |= ((xf ^ yf) & M) >>> 8; //quotient byteに商の符号を入れる
this.flg = xf;
} else { //ieeerem(x,±Inf)=x
epbFpsr |= ((xf ^ yf) & M) >>> 8; //quotient byteに商の符号を入れる
this.finish (xf, x.epp, x.dvl, x.cvl, 0L); //xが非正規化数のときUFをセットする
}
return this;
}
//両方±0,±Inf,NaN以外
epbFpsr |= ((xf ^ yf) & M) >>> 8; //quotient byteに商の符号を入れる
if (false) {
this.inner ();
//this.sub (x, new EFP ().div (x, y).rint ().imul (y)); //x-rint(x/y)*y。this==x||this==yの場合に注意
EFP q = new EFP ().quo (x, y); //商
int qi = q.geti32abs (); //商の絶対値の下位32bit
EFP w = new EFP ();
this.imulw (w, q, y).negsub (x).sub (w); //余り。桁落ちを避けるため倍精度で計算する
int k = w.imul2 (this).cmpabs (y); //|余り*2|<=>|除数|
if (k > 0 || k == 0 && (qi & 1) != 0) { //余りの絶対値が除数の絶対値の1/2よりも大きいか、ちょうど1/2で商が奇数のとき
qi++; //商の絶対値を1増やす
if ((xf ^ yf) >= 0) {
this.sub (y);
} else {
this.iadd (y);
}
}
epbQuotient = qi;
epbFpsr |= (qi & 127) << 16; //商の絶対値の下位7bit
if (this.flg << 1 < 0) { //余りが0
this.flg = xf | Z; //0にxの符号を付ける
}
return this.outer ().finish ();
} else {
this.inner ();
int ye = y.epp; //this==yの場合があるので順序に注意する
long yd = y.dvl;
long yc = y.cvl;
long yc1 = yc >>> 1;
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
int i;
long l;
int q = 0;
if ((i = this.epp - ye) > 0 ||
i == 0 && ((l = this.dvl - yd) > 0L ||
l == 0L && this.cvl >>> 1 >= yc1)) { //|x|>=|y|。商は0ではない
this.flg = P; //|x|。余りの初期値
EFP t = new EFP (P, 0, yd, yc);
do {
t.epp = i = (l = this.dvl - yd) > 0L || l == 0L && this.cvl >>> 1 >= yc1 ? this.epp : this.epp - 1; //指数部を揃えて
if ((i -= ye) <= 31) {
q |= 1 << i;
}
this.sub (t); //引く。アンダーフローのチェックは後で行う
} while (this.flg == 0 && //0ではない
((i = this.epp - ye) > 0 ||
i == 0 && ((l = this.dvl - yd) > 0L ||
l == 0L && this.cvl >>> 1 >= yc1))); //this>=|y|。まだ引ける。指数部が極端に違うと繰り返す回数が大きくなる
this.flg |= xf; //余りが0の場合も含めてyの符号に関係なくxの符号を付ける
} else { //|x|<|y|。商は0
this.flg = xf; //被除数がそのまま余りになる
}
if (this.flg << 1 >= 0) { //余りが0ではないとき
if ((i = this.epp - ye + 1) > 0 ||
i == 0 && ((l = this.dvl - yd) > 0L ||
l == 0L && ((l = (this.cvl >>> 1) - yc1) > 0L || //|r|>|y|/2または
l == 0L && (q & 1) != 0))) { //|r|==|y|/2かつ商が奇数
this.sub (new EFP (this.flg, ye, yd, yc)); //符号を合わせて引く。アンダーフローのチェックは後で行う
q++;
}
if ((short) this.epp != this.epp) { //アンダーフロー
this.outer ();
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = this.flg & M;
epbExceptionOperandMantissa = this.dvl;
return this.sete (UNFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±0
}
}
epbQuotient = q;
epbFpsr |= (q & 127) << 16; //商の絶対値の下位7bit
return this.outer ().finish ();
}
} //efp.ieeerem(EFP,EFP)
//------------------------------------------------------------------------
//k = x.ieeerempi2 ()
// k=rint(x/(pi/2))&3
// x=x-rint(x/(pi/2))*(pi/2)
//k = y.ieeerempi2 (x)
// k=rint(x/(pi/2))&3
// y=x-rint(x/(pi/2))*(pi/2)
// ラジアンの象限分類
//
// 引数をpi/2で割った余りを[-pi/4..pi/4]の範囲で求めて商の下位2bitを返す
// k=1
// │ ←
// k=2↓\ │ /
// \ │ /
// \│/
// ────・────
// /│\
// / │ \
// / │ \↑k=0
// → │
// k=3
//
// 三角関数に与えられた引数が大きすぎる場合は何かの間違いでその引数と結果は意味を持たないと考えられる
// しかし実装としてはどのような引数が与えられても可能な限り真の値に近い結果を返したい
// sin(2^n)の象限分類を行うにはおよそ(n)bitの円周率を静的または動的に調達する必要がある
// xをyで割った余りx%y=x-trunc(x/y)*yを正確に求めるには商trunc(x/y)を1の位まで正確に求めなければならない
// xの指数部に対してyの有効桁数が少ないと商を1の位まで正確に求めることができない
// yがpi/2のときxが2^nならばyのpi/2もおよそ(n)bitなければならない
// 除数が定数のときは除算を逆数乗算で置き換えることができる
// 除数yがpi/2なのでxの指数部の最大値と同じ桁数の2/piの値があればよい
// 象限分類で必要なのは商の下位2bitと余りの先頭LENbitだけである
// 2/piの値の配列が大きくても1回の呼び出しで使用するのはその一部分に限られる
//
// echo lm=32767;lw=9;default(realprecision,floor(lm*0.30103)+200);pi2=Pi/2;twopi=2/Pi;ln2=log(2);eval("hex(s)={my(v,h,i,c);v=Vecsmall(s);h=0;for(i=1,#v,c=v[i];if(c!=95,h=(h<<4)+if(48<=c&&c<=57,c-48,65<=c&&c<=70,c-55,97<=c&&c<=102,c-87,error)));h}");p=eval("twopi/2^(31*3)");a=vector((3+(lm+600)\31)\10*10,i,p=p*eval("2^31");w=floor(p);p=frac(p);printf("%s0x%08x,%s",if(i%10==1," ",""),w,if(i%10==0,"\n"," "));w);for(ee=0,lm,xx=hex("80000000000000000000000");tx=eval("xx/2^(91-ee)");tk=bitand(tx\pi2,3);ty=tx%pi2;yy=sum(i=1,lw,shift(a[ee\31+i],31*(lw-i)));ay=frac(xx*yy\eval("2^31")/eval("2^(31*(lw-1)-ee%31)"))*4;ak=floor(ay);ay=frac(ay)*pi2;dist=if(tk!=ak,-999,-log(abs((ay-ty)/ty))/ln2);printf(" // %6d %023x %d %32.30f %d %32.30f %6.2f %s%c",ee,xx,tk,ty,ak,ay,dist,if(eval("dist<96"),"ERROR","OK"),10)) | gp -q | grep "ERROR"
// エラーなし
// echo lm=32767;lw=9;default(realprecision,floor(lm*0.30103)+200);pi2=Pi/2;twopi=2/Pi;ln2=log(2);eval("hex(s)={my(v,h,i,c);v=Vecsmall(s);h=0;for(i=1,#v,c=v[i];if(c!=95,h=(h<<4)+if(48<=c&&c<=57,c-48,65<=c&&c<=70,c-55,97<=c&&c<=102,c-87,error)));h}");p=eval("twopi/2^(31*3)");a=vector((3+(lm+600)\31)\10*10,i,p=p*eval("2^31");w=floor(p);p=frac(p);printf("%s0x%08x,%s",if(i%10==1," ",""),w,if(i%10==0,"\n"," "));w);for(ee=0,lm,xx=hex("fffffffffffffffffffffff");tx=eval("xx/2^(91-ee)");tk=bitand(tx\pi2,3);ty=tx%pi2;yy=sum(i=1,lw,shift(a[ee\31+i],31*(lw-i)));ay=frac(xx*yy\eval("2^31")/eval("2^(31*(lw-1)-ee%31)"))*4;ak=floor(ay);ay=frac(ay)*pi2;dist=if(tk!=ak,-999,-log(abs((ay-ty)/ty))/ln2);printf(" // %6d %023x %d %32.30f %d %32.30f %6.2f %s%c",ee,xx,tk,ty,ak,ay,dist,if(eval("dist<96"),"ERROR","OK"),10)) | gp -q | grep "ERROR"
// エラーなし
//
//2/piの値
// echo lm=32767;lw=9;default(realprecision,floor(lm*0.30103)+200);pi2=Pi/2;twopi=2/Pi;ln2=log(2);eval("hex(s)={my(v,h,i,c);v=Vecsmall(s);h=0;for(i=1,#v,c=v[i];if(c!=95,h=(h<<4)+if(48<=c&&c<=57,c-48,65<=c&&c<=70,c-55,97<=c&&c<=102,c-87,error)));h}");p=eval("twopi/2^(31*3)");a=vector((3+(lm+600)\31)\10*10,i,p=p*eval("2^31");w=floor(p);p=frac(p);printf("%s0x%08x,%s",if(i%10==1," ",""),w,if(i%10==0,"\n"," "));w);for(ee=0,lm,xx=hex("c90fdaa22168c234c4c6629");tx=eval("xx/2^(91-ee)");tk=bitand(tx\pi2,3);ty=tx%pi2;yy=sum(i=1,lw,shift(a[ee\31+i],31*(lw-i)));ay=frac(xx*yy\eval("2^31")/eval("2^(31*(lw-1)-ee%31)"))*4;ak=floor(ay);ay=frac(ay)*pi2;dist=if(tk!=ak,-999,-log(abs((ay-ty)/ty))/ln2);printf(" // %6d %023x %d %32.30f %d %32.30f %6.2f %s%c",ee,xx,tk,ty,ak,ay,dist,if(eval("dist<96"),"ERROR","OK"),10)) | gp -q > two_pi_array.out
// エラーなし
//
public int ieeerempi2 () {
return this.ieeerempi2 (this);
} //efp.ieeerempi2()
public int ieeerempi2 (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf; //そのまま
return 0;
}
//±0,±Inf,NaN以外
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
int o;
long t;
if ((o = xe + 1) < 0 || o == 0 && ((t = xd - 0xc90fdaa22168c234L) < 0L ||
t == 0L && xc >>> 1 <= 0xc4c6629L >>> 1)) { //|x|<=pi/4
this.flg = xf; //そのまま
this.epp = xe;
this.dvl = xd;
this.cvl = xc;
return 0;
}
if ((o = xe - 1) < 0 || o == 0 && ((t = xd - 0x96cbe3f9990e91a7L) < 0L ||
t == 0L && xc >>> 1 <= 0x9394c9fL >>> 1)) { //|x|<=3*pi/4
if (xf >= 0) {
this.inner ().sub (x, PI_2).outer ().sub (PI_2A); //x-pi/2
return 1;
} else {
this.inner ().iadd (x, PI_2).outer ().add (PI_2A); //x+pi/2
return 3;
}
}
//以下はxe>=1
//92bitの仮数部を30bit,31bit,31bitに3分割する
long x0 = xd >>> -30; //上位30bit
long x1 = xd >>> 3 & 0x7fffffffL; //中位31bit
long x2 = (xd << 28 | xc >>> -28) & 0x7fffffffL; //下位31bit
// perl optdiv.pl 32767 31
// x/31==x*16913>>>19 (0<=x<=34966) [32767*16913==554188271]
o = xe * 16913 >>> 19; //xe/31。xe<0は不可
long y0 = TWO_PI_ARRAY[o ];
long y1 = TWO_PI_ARRAY[o + 1];
long y2 = TWO_PI_ARRAY[o + 2];
long y3 = TWO_PI_ARRAY[o + 3];
long y4 = TWO_PI_ARRAY[o + 4];
long y5 = TWO_PI_ARRAY[o + 5];
long y6 = TWO_PI_ARRAY[o + 6];
long y7 = TWO_PI_ARRAY[o + 7];
long y8 = TWO_PI_ARRAY[o + 8];
//xとyを掛けて62bit左詰め4要素にする
// x0 x1 x2
// * y0 y1 y2 y3 y4 y5 y6 y7 y8
// -----------------------------------
// | | | | x2*y8
// | | | |x1*y8|
// | | | |x2*y7|
// | | | x0*y8 |
// | | | x1*y7 |
// | | | x2*y6 |
// | | |x0*y7| |
// | | |x1*y6| |
// | | |x2*y5| |
// | | x0*y6 | |
// | | x1*y5 | |
// | | x2*y4 | |
// | |x0*y5| | |
// | |x1*y4| | |
// | |x2*y3| | |
// | x0*y4 | | |
// | x1*y3 | | |
// | x2*y2 | | |
// |x0*y3| | | |
// |x1*y2| | | |
// |x2*y1| | | |
// x0*y2 | | | |
// x1*y1 | | | |
// x2*y0 | | | |
// x0*y1| | | | |
// x1*y0| | | | |
// x0*y0 | | | | |
// -----------------------------------
// z0 z1 z2 z3
long z3 = (x2 * y8 >>> 31) + x1 * y8 + x2 * y7; //x2*y8の下位は捨てる
long z2 = (z3 >>> 31) + x0 * y8 + x1 * y7 + x2 * y6;
z3 = (z3 & 0x7fffffffL) + (z2 << 33 >>> 2) << 2;
z2 = (z2 >>> 31) + x0 * y7 + x1 * y6 + x2 * y5;
long z1 = (z2 >>> 31) + x0 * y6 + x1 * y5 + x2 * y4;
z2 = (z2 & 0x7fffffffL) + (z1 << 33 >>> 2) << 2;
z1 = (z1 >>> 31) + x0 * y5 + x1 * y4 + x2 * y3;
long z0 = (z1 >>> 31) + x0 * y4 + x1 * y3 + x2 * y2;
z1 = (z1 & 0x7fffffffL) + (z0 << 33 >>> 2) << 2;
z0 = (z0 >>> 31) + x0 * y3 + x1 * y2 + x2 * y1 + (x0 * y2 + x1 * y1 + x2 * y0 << 31) << 2; //溢れは無視する。x0*y1+x1*y0とx0*y0は不要
//248bit左詰めにする
z0 |= z1 >>> -2;
z1 = z1 << 2 | z2 >>> -4;
z2 = z2 << 4 | z3 >>> -6;
z3 <<= 6;
//左にxe%31bitずらす
o = xe - o * 31; //xe%31
if (o != 0) {
z0 = z0 << o | z1 >>> -o;
z1 = z1 << o | z2 >>> -o;
z2 = z2 << o | z3 >>> -o;
z3 <<= o;
}
//商の下位2bitを取り出す
o = (int) (z0 >>> -2);
if (xf < 0) {
o = -o;
}
//商の下位2bitを押し出して小数点以下だけにする
z0 = z0 << 2 | z1 >>> -2;
z1 = z1 << 2 | z2 >>> -2;
z2 = z2 << 2 | z3 >>> -2;
z3 <<= 2;
//余りの絶対値が0.5以上のときは商の絶対値を1増やして余りの絶対値を1減らす
// 左端が0.5の位なので左端が1ならば符号を反転する
if (z0 < 0L) {
o = xf >= 0 ? o + 1 : o - 1;
t = z3 = -z3;
t |= z2 = t == 0L ? -z2 : ~z2;
t |= z1 = t == 0L ? -z1 : ~z1;
z0 = t == 0L ? -z0 : ~z0; //左端が0になるとは限らない。100...のときは符号反転しても100...のまま
xf ^= M;
}
o &= 3;
//正規化する
if (z0 < 0L) {
xe = -1; //-1
} else if (z0 != 0L) {
xe = Long.numberOfLeadingZeros (z0); //1..63。左にシフトするbit数
z0 = z0 << xe | z1 >>> -xe;
z1 = z1 << xe | z2 >>> -xe;
z2 = z2 << xe | z3 >>> -xe;
z3 <<= xe;
xe = ~xe; //-1-xe。-2..-64。指数
} else if (z1 < 0L) {
xe = -65; //-65。指数
z0 = z1;
z1 = z2;
z2 = z3;
z3 = 0L;
} else if (z1 != 0L) {
xe = Long.numberOfLeadingZeros (z1) + 64; //65..127。左にシフトするbit数
z0 = z1 << xe | z2 >>> -xe;
z1 = z2 << xe | z3 >>> -xe;
z2 = z3 << xe;
z3 = 0L;
xe = ~xe; //-1-xe。-66..-128。指数
} else if (z2 < 0L) {
xe = -129; //-129。指数
z0 = z2;
z1 = z3;
z2 = 0L;
z3 = 0L;
} else if (z2 != 0L) {
xe = Long.numberOfLeadingZeros (z2) + 128; //129..191。左にシフトするbit数
z0 = z2 << xe | z3 >>> -xe;
z1 = z3 << xe;
z2 = 0L;
z3 = 0L;
xe = ~xe; //-1-xe。-130..-192。指数
} else if (z3 != 0L) {
xe = Long.numberOfLeadingZeros (z3) + 192; //192..255。左にシフトするbit数
z0 = z3 << xe;
z1 = 0L;
z2 = 0L;
z3 = 0L;
xe = ~xe; //-1-xe。-193..-256。指数
} else {
this.flg = xf | Z;
return o;
}
//丸めの処理
this.ifinish (xf, xe, z0, z1, z2 | z3);
//pi/2を掛ける
this.mul (PI_2);
//商の下位2bitを返す
return o;
} //efp.ieeerempi2(EFP)
//------------------------------------------------------------------------
//x = x.inc ()
// x+=1
//y = y.inc (x)
// y=x+1
// 1を加える(インクリメント)
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{$_[0]+1});print$g"
// echo read("../misc/efp.gp");eval("inc(x)=x+1");graph(inc) | gp -q
// +---------+---------+---------+---------+---------+---------+--------***--------+
// | | *** |
// | | *** |
// | | *** |
// | | *** |
// + + *** +
// | | *** |
// | | *** |
// | | *** |
// | | *** |
// + + *** +
// | | *** |
// | | *** |
// | | *** |
// | |*** |
// + *** +
// | ***| |
// | *** | |
// | *** | |
// | *** | |
// +---------+---------+--------***--------+---------+---------+---------+---------+
// | *** | |
// | *** | |
// | *** | |
// | *** | |
// + *** + +
// | *** | |
// | *** | |
// | *** | |
// | *** | |
// + *** + +
// | *** | |
// | *** | |
// | *** | |
// |*** | |
// ** + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
public final EFP inc () {
return this.inc (this);
} //efp.inc()
public final EFP inc (EFP x) {
//return this.add (x, ONE); //7.6ns
//6.2ns
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
this.flg = P; //+1
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
} else { //±Inf,NaN
this.flg = xf;
}
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp;
if (xe < -LEN) { //..-LEN-1。xの先頭がguard bitよりも右
//絶対値は1の方が大きいのでxを右にシフトするがxの絶対値が小さすぎるので1になる
epbFpsr |= EPB_FPSR_X2; //不正確な結果
this.flg = P; //+1
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
return this;
}
long xd = x.dvl;
long xc = x.cvl;
if (LEN < xe) { //LEN+1..。1がguard bitよりも右
//絶対値はxの方が大きいので1を右にシフトするが1の絶対値が小さすぎるのでxになる
epbFpsr |= EPB_FPSR_X2; //不正確な結果
return this.finish (xf, xe, xd, xc, 0L); //x
}
long xb = 0L;
if (xe == 0) { //0。xの最上位bitと1が重なる
//絶対値はxの方が大きいか等しいが小数点の位置は同じ
if (xf < 0) { //-x
//絶対値から1を引く
xd -= MSB;
} else { //+x
//絶対値に1を加える
xb = xc << -1;
xc = xd << -1 | xc >>> 1;
xd = (xd >>> 1) + (MSB >>> 1);
xe++;
}
} else if (0 < xe) { //1..LEN
//絶対値はxの方が大きいので1を右にシフトする
if (xf < 0) { //-x
//絶対値から1を引く
if (xe <= 63) { //1..63。xの上位の2bit目以降と1が重なる
xd -= MSB >>> xe; //最上位bitが1なのでボローはなく0にもならない
} else { //64..LEN。xの下位またはguard bitと1が重なる
if (xc >>> ~xe != 0L) { //下位の引く位置から上が0ではない。下位だけで引ける
xc -= MSB >>> xe;
} else { //下位の引く位置から上が0なのでボローが発生する
xc |= MSB >> xe; //下位の引く位置から上は-1になる
xd--; //ボローを上位から引く
}
}
} else { //+x
//絶対値に1を加える
if (xe <= 63) { //1..63。xの上位と1が重なる
if ((xd += MSB >>> xe) >>> ~xe == 0L) { //絶対値に1を加えたら加えたbitから上がすべて0になって溢れた
xb = xc << -1;
xc = xd << -1 | xc >>> 1;
xd = MSB | xd >>> 1;
xe++;
}
} else { //64..LEN。xの下位またはguard bitと1が重なる
if ((xc += MSB >>> xe) >>> ~xe == 0L && ++xd == 0L) { //絶対値に1を加えたら加えたbitから上がすべて0になって溢れた
xb = xc << -1;
xc = xc >>> 1;
xd = MSB;
xe++;
}
}
}
} else { //-LEN..-1
//絶対値は1の方が大きいのでxを右にシフトする
if (-63 <= xe) { //-63..-1。xの先頭が1の右隣から上位の最下位bitまで
xb = xc << xe;
xc = xd << xe | xc >>> -xe;
xd >>>= -xe;
} else if (-64 == xe) { //-64。xの先頭が下位の最上位bit
xb = xc;
xc = xd;
xd = 0L;
} else { //-LEN..-65。xの先頭が下位の上から2bit目からguard bitまで
xb = xd << xe | xc >>> -xe;
xc = xd >>> -xe;
xd = 0L;
}
xe = 0;
if (xf < 0) { //-x
//絶対値を1から引く
if (xb != 0L) {
xb = -xb;
xc = -1L - xc;
xd = MSB - 1L - xd;
} else if (xc != 0L) {
xc = -xc;
xd = MSB - 1L - xd;
} else {
xd = MSB - xd;
}
xf ^= M; //符号反転
} else { //+x
//絶対値に1を加える
xd |= MSB;
}
}
//正規化する
if (xd >= 0L) {
if (xd != 0L) {
int o = Long.numberOfLeadingZeros (xd); //1..63。左にシフトするbit数
xe -= o;
xd = xd << o | xc >>> -o;
xc = xc << o | xb >>> -o;
xb <<= o;
} else if (xc < 0L) {
xe -= 64;
xd = xc;
xc = xb;
xb = 0L;
} else if (xc != 0L) {
int o = 64 + Long.numberOfLeadingZeros (xc); //65..127。左にシフトするbit数
xe -= o;
xd = xc << o | xb >>> -o;
xc = xb << o;
xb = 0L;
} else if (xb < 0L) {
xe -= 128;
xd = xb;
xc = 0L;
xb = 0L;
} else if (xb != 0L) {
int o = 128 + Long.numberOfLeadingZeros (xb); //129..191。左にシフトするbit数
xe -= o;
xd = xb << o;
xc = 0L;
xb = 0L;
} else {
this.flg = P | Z; //-1+1=+0
return this;
}
}
return this.finish (xf, xe, xd, xc, xb);
} //efp.inc(EFP)
//------------------------------------------------------------------------
//b = x.iseven ()
// 偶数の整数か
//
// NaNは偶数ではない
// ±0,±Infは偶数
// ±0,±Inf,NaN以外は1の位のbitがないか1の位のbitが0ならば偶数
//
public boolean iseven () {
int xf = this.flg;
int xe = this.epp;
return (xf << 1 != 0 ? xf << 3 >= 0 : //±0,±Infは偶数。NaNは整数ではない
xe < 0 ? false : //整数部の1が小数点よりも右側にあるということは小数点以下が0ではないので整数ではない
xe > LEN - 1 ? true : //1の位が小数部よりも右側にあるということは1の位が0なので偶数
xe <= 63 ? this.dvl << xe == 0L && this.cvl == 0L : this.cvl << xe == 0L); //1の位と小数点以下がすべて0ならば偶数
} //efp.iseven()
//------------------------------------------------------------------------
//b = x.isinf ()
// ±Infか
//
public boolean isinf () {
return this.flg << 2 < 0; //±Inf
} //efp.isinf()
//------------------------------------------------------------------------
//b = x.isint ()
// 整数か
//
// NaNは整数ではない
// ±0,±Infは整数
// ±0,±Inf,NaN以外は小数点よりも右側にセットされているbitがなければ整数
//
public boolean isint () {
int xf = this.flg;
int xe = this.epp;
return (xf << 1 != 0 ? xf << 3 >= 0 : //±0,±Infは整数。NaNは整数ではない
xe < 0 ? false : //整数部の1が小数点よりも右側にあるということは小数点以下が0ではないので整数ではない
xe >= LEN - 1 ? true : //小数点が小数部よりも右側にあるので整数
xe <= 63 ? this.dvl << 1 << xe == 0L && this.cvl == 0L : this.cvl << xe == 0L); //小数点以下がすべて0ならば偶数
} //efp.isint()
//------------------------------------------------------------------------
//b = x.isnan ()
// NaNか
//
public boolean isnan () {
return this.flg << 3 < 0; //NaN
} //efp.isnan()
//------------------------------------------------------------------------
//b = x.isodd ()
// 奇数の整数か
//
// NaNは奇数ではない
// ±0,±Infは奇数ではない
// ±0,±Inf,NaN以外は1の位のbitが1ならば奇数
//
public boolean isodd () {
int xf = this.flg;
int xe = this.epp;
return (xf << 1 != 0 ? false : //±0,±Infは奇数ではない。NaNは整数ではない
xe < 0 ? false : //整数部の1が小数点よりも右側にあるということは小数点以下が0ではないので整数ではない
xe > LEN - 1 ? false : //1の位が小数部よりも右側にあるということは1の位が0なので奇数ではない
xe <= 63 ? this.dvl << xe == MSB && this.cvl == 0L : this.cvl << xe == MSB); //1の位が1で小数点以下がすべて0ならば奇数
} //efp.isodd()
//------------------------------------------------------------------------
//b = x.isone ()
// +1か
//
public boolean isone () {
return (this.flg == P &&
this.epp == 0 &&
this.dvl == MSB &&
this.cvl == 0L); //1
} //efp.isone()
//------------------------------------------------------------------------
//b = x.iszero ()
// ±0か
//
public boolean iszero () {
return this.flg << 1 < 0; //±0
} //efp.iszero()
//------------------------------------------------------------------------
//b = x.le (y)
// b=x<=y
// より小さいか等しいか
//
// -Inf==-Inf<-x<-0==+0<+x<+Inf==+Inf
//
// NaNの扱い
// どちらかがNaNのときはfalseを返す
//
public boolean le (EFP y) {
int xf = this.flg;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
return EFP_LE_TABLE[xf >>> 28] << (yf >>> 28 - 1) < 0;
}
//両方±0,±Inf,NaN以外
if (xf != yf) { //両方±0,±Inf,NaN以外で符号が違う
return xf < yf;
}
//両方±0,±Inf,NaN以外で符号が同じ
int s;
long t;
return (xf >= 0 ? 1 : -1) * ((s = this.epp - y.epp) != 0 ? s >= 0 ? 1 : -1 :
(t = this.dvl - y.dvl) != 0L ? t >= 0L ? 1 : -1 :
(t = (this.cvl >>> 1) - (y.cvl >>> 1)) != 0L ? t >= 0L ? 1 : -1 :
0) <= 0;
} //efp.le(EFP)
//------------------------------------------------------------------------
//x = x.log ()
// x=log(x)
//y = y.log (x)
// y=log(x)
// 自然対数 natural logarithm
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{log($_[0])});print$g"
// echo read("../misc/efp.gp");graph(log) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | ****
// | | ******** |
// + + ****** +
// | | ****** |
// | | ***** |
// | | **** |
// | | *** |
// +---------+---------+---------+---------+--------***--------+---------+---------+
// | | *** |
// | | ** |
// | | ** |
// | | ** |
// + + ** +
// | | * |
// | | ** |
// | | * |
// | |** |
// + +* +
// | |* |
// | |* |
// | |* |
// | |* |
// + ** +
// | * |
// | * |
// | * |
// | * |
// +---------+---------+---------+---------*---------+---------+---------+---------+
//
// 定義域
// 0<x<=inf
//
// 値域
// -inf<=y<=inf
//
// テイラー展開
// > coeff(sub(a=0,for n:=0:8 sum sub(x=a,df(log(1+x),x,n))/factorial(n)*(x-a)^n),x);
// - 1 1 - 1 1 - 1 1 - 1
// {0,1,------,---,------,---,------,---,------}
// 2 3 4 5 6 7 8
// log(1+x)=sum[n=1..inf]{(-1)^(n+1)*x^n/n}
// 1<xのときはlog(x)=-log(1/x)で計算する
//
// テイラー展開2
// log(1+x)=sum[n=1..inf]{(-1)^(n+1)*x^n/n}
// xに-xを代入すると偶数次の項は係数が負のままで奇数次の項は係数が正から負に変わるので
// log(1-x)=sum[n=1..inf]{-x^n/n}
// > coeff(sub(a=0,for n:=0:8 sum sub(x=a,df(log(1-x),x,n))/factorial(n)*(x-a)^n),x);
// - 1 - 1 - 1 - 1 - 1 - 1 - 1
// {0,-1,------,------,------,------,------,------,------}
// 2 3 4 5 6 7 8
// これらを引くと偶数次の項が消えて
// log(1+x)-log(1-x)=2*sum[k=0..inf]{x^(2*k+1)/(2*k+1)}
// すなわち
// log((1+x)/(1-x))=2*sum[k=0..inf]{x^(2*k+1)/(2*k+1)}
// > coeff(sub(a=0,for n:=0:14 sum sub(x=a,df(log((1+x)/(1-x)),x,n))/factorial(n)*(x-a)^n),x);
// 2 2 2 2 2 2
// {0,2,0,---,0,---,0,---,0,---,0,----,0,----}
// 3 5 7 9 11 13
// ここで
// u=(x-1)/(x+1)
// とおくと
// x=(1+u)/(1-u)
// であるから
// log(x)=2*sum[k=0..inf]{u^(2*k+1)/(2*k+1)}
// 0<x<infのとき-1<u<1なので定義域のほぼ全域で収束する
// それでもxが1から離れると収束が遅い
// 式からわかるように、log(x)のグラフと2*(x-1)/(x+1)のグラフは1付近の形がよく似ている
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{my($x)=@_;2*($x-1)/($x+1)});print$g"
// +--------***--------+---------+---------+---------+---------+---------+---------+
// | **** | |
// | **** | |
// **** | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | *******
// + + ********* +
// | | ****** |
// | | ***** |
// | | **** |
// | | **** |
// +---------+---------+---------+---------+--------***--------+---------+---------+
// | | *** |
// | | ** |
// | | ** |
// | | ** |
// + + ** +
// | | ** |
// | |** |
// | |* |
// | ** |
// + * +
// | ** |
// | *| |
// | *| |
// | **| |
// + * + +
// | * | |
// | ** | |
// | * | |
// | * | |
// +---------+---------+---------+------*--+---------+---------+---------+---------+
// 差を10倍してみる
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{my($x)=@_;10*(2*($x-1)/($x+1)-log($x))});print$g"
// +---------+---------+---------+---------+-*-------+---------+---------+---------+
// | | * |
// | | * |
// | | * |
// | | * |
// + + * +
// | | * |
// | | * |
// | | * |
// | | * |
// + + * +
// | | ** |
// | | * |
// | | * |
// | | * |
// + + * +
// | | ** |
// | | * |
// | | ** |
// | | ** |
// +---------+---------+---------+---------+-----***********---+---------+---------+
// | | ****** |
// | | **** |
// | | *** |
// | | **** |
// + + *** +
// | | **** |
// | | *** |
// | | *** |
// | | ***
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
// テイラー展開3
// 浮動小数点数の特性を利用して指数部を分離する
// x=2^k*vのとき
// log(x)=log(2^k*v)
// =k*log(2)+log(v)
// sqrt(2)/2<=v<=sqrt(2)
// となるようにkを選ぶと
// 2*sqrt(2)-3<=(v-1)/(v+1)<=3-2*sqrt(2)
// -0.17157...<=(v-1)/(v+1)<=0.17157...
// となる
// 1/(3-2*sqrt(2))^2=33.97...であるから1項増やす毎に5bit以上増える
// 多倍長の場合はxと同じ精度のlog(2)を他の方法で求めなければならない
// echo read("../misc/efp.gp");eval("f(n,x)={my(u=(x-1)/(x+1));2*sum(k=0,n,u^(2*k+1)/(2*k+1))}");for(n=0,30,printf("%4d",floor(closeness2(log,f(n,x),sqrt(2)/2,sqrt(2))))) | gp -q
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// 6 12 18 23 28 34 39 44 49 55 60 65 70 76 81 86 91 96 101 107 112 117 122 127 132 137 143 148 153 158 163
//
// 連分数展開
// log(1+x)=x/(1+x/(2+x/(3+4*x/(4+4*x/(5+9*x/(6+9*x/(7+...
// echo eval("h(k)=if(k==1,1/2,bitand(k,1)==0,k/(k+1)/4,(k+1)/k/4)");eval("g(n,x,k)=h(k)*x/(1+if(k<n,g(n,x,k+1),0))");eval("f(n,x)=x/(1+if(n<1,0,g(n,x,1)))");for(n=0,10,print(" // f(",n,",x)=",f(n,x))) | gp -q
// f(0,x)=x
// f(1,x)=2*x/(x + 2)
// f(2,x)=(x^2 + 6*x)/(4*x + 6)
// f(3,x)=(3*x^2 + 6*x)/(x^2 + 6*x + 6)
// f(4,x)=(x^3 + 21*x^2 + 30*x)/(9*x^2 + 36*x + 30)
// f(5,x)=(11*x^3 + 60*x^2 + 60*x)/(3*x^3 + 36*x^2 + 90*x + 60)
// f(6,x)=(3*x^4 + 140*x^3 + 510*x^2 + 420*x)/(48*x^3 + 360*x^2 + 720*x + 420)
// f(7,x)=(25*x^4 + 260*x^3 + 630*x^2 + 420*x)/(6*x^4 + 120*x^3 + 540*x^2 + 840*x + 420)
// f(8,x)=(6*x^5 + 505*x^4 + 3360*x^3 + 6510*x^2 + 3780*x)/(150*x^4 + 1800*x^3 + 6300*x^2 + 8400*x + 3780)
// f(9,x)=(137*x^5 + 2310*x^4 + 9870*x^3 + 15120*x^2 + 7560*x)/(30*x^5 + 900*x^4 + 6300*x^3 + 16800*x^2 + 18900*x + 7560)
// f(10,x)=(5*x^6 + 672*x^5 + 7035*x^4 + 23520*x^3 + 30870*x^2 + 13860*x)/(180*x^5 + 3150*x^4 + 16800*x^3 + 37800*x^2 + 37800*x + 13860)
// echo read("../misc/efp.gp");eval("log1p(x)=log(1+x)");eval("h(k)=if(k==1,1/2,k%2==0,k/(k+1)/4,(k+1)/k/4)");eval("g(n,x,k)=h(k)*x/(1+if(k<n,g(n,x,k+1),0))");eval("f(n,x)=x/(1+if(n<1,0,g(n,x,1)))");for(n=0,30,printf("%4d",floor(closeness2(log1p,f(n,x),sqrt(2)/2-1,sqrt(2)-1)))) | gp -q
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// 2 6 9 13 16 20 23 27 31 34 38 41 45 48 52 55 59 62 66 70 73 77 80 84 87 91 94 98 101 105 108
//
// チェビシェフ展開
// x=(1+u)/(1-u)
// u=(x-1)/(x+1)
// log((1+u)/(1-u))=2*sum[k=0..inf]{u^(2*k+1)/(2*k+1)}
// の係数を調整する
// sqrt(2)/2<=x<=sqrt(2)
// のとき
// 2*sqrt(2)-3<=u<=3-2*sqrt(2)
// であるから
// echo read("../misc/efp.gp");eval("f(u)=log((1+u)/(1-u))");a=2*sqrt(2)-3;b=3-2*sqrt(2);for(k=0,30,printf("%4d",floor(closeness2(f,chebyshev(f,a,b,2*k+1),a,b)))) | gp -q
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// 7 14 21 28 35 42 49 56 63 70 77 84 91 98 105 113 120 127 134 141 148 155 162 169 176 183 190 197 204 211 219
//
// expm1を高速に計算できる場合
// 組み込み関数を使ってlog(x)=log1p(x-1)の近似値y'を求める
// expm1を使ってx'-1=expm1(y')を正確に求める。これは正確なのでlog(x')=y'である
// log(x)=log(x'*(x/x'))
// =log(x')+log(x/x')
// =y'+log((x'+x-x')/x')
// =y'+log(1+(x-x')/x')
// =y'+log1p((x'-x)/x)
// (x-x')/xは小さいのでlog1p((x-x')/x')は速く収束する
//
// AGM
// I(a,b)=int[0..pi/2]{dt/sqrt(a^2*cos(t)^2+b^2*sin(t)^2)}
// T(a,b)=2/pi*I(a,b)=1/M(a,b)
// M(a[0],b[0])=lim[n=inf]{a[n]}=lim[n=inf]{b[n]}
// a[n+1]=(a[n]+b[n])/2
// b[n+1]=sqrt(a[n]*b[n])
// abs(log(x)-[I(1,10^-n)-I(1,10^-n*x)])<n*10^(2-2*n) (0<x<1)
// echo read("../misc/efp.gp");eval("fi(a,b)=intnum(t=0,Pi/2,1/sqrt(a^2*cos(t)^2+b^2*sin(t)^2))");eval("f(n,x)=fi(1,2^-n)-fi(1,2^-n*x)");printf("%.30f",f(100,2)/f(100,10)) | gp -q
// 0.301029995663981195213738894724
// echo read("../misc/efp.gp");eval("g(a,b)=Pi/2/agm(a,b)");eval("f(n,x)=g(1,2^-n)-g(1,2^-n*x)");printf("%.30f",f(100,2)/f(100,10)) | gp -q
// 0.301029995663981195213738894724
// perl -e "sub mm{my($a,$b)=@_;while(1){my$t=($a+$b)/2;$t<$a or last;$b=sqrt($a*$b);$a=$t}$a};sub ii{my($a,$b)=@_;atan2(1,1)*2/mm($a,$b)}sub ll{my($x,$n)=@_;ii(1,2**-$n)-ii(1,2**-$n*$x)}printf' // %14s %22s %22s %22s%c','x','log(x)','ll(x,31)','abs(ll(x,31)-log(x))',10;for my$k(-10..10){my$x=10**$k;printf' // %14.14g %22.16g %22.16g %22.16g%c',$x,log($x),ll($x,31),abs(log($x)-ll($x,31)),10}"
// x log(x) ll(x,31) abs(ll(x,31)-log(x))
// 1e-10 -23.02585092994046 -23.02585092994045 3.552713678800501e-15
// 1e-09 -20.72326583694641 -20.7232658369464 7.105427357601002e-15
// 1e-08 -18.42068074395237 -18.42068074395237 0
// 1e-07 -16.11809565095832 -16.11809565095832 3.552713678800501e-15
// 1e-06 -13.81551055796427 -13.81551055796427 0
// 1e-05 -11.51292546497023 -11.51292546497024 8.881784197001252e-15
// 0.0001 -9.210340371976182 -9.21034037197618 1.77635683940025e-15
// 0.001 -6.907755278982137 -6.907755278982144 7.105427357601002e-15
// 0.01 -4.605170185988091 -4.605170185988086 4.440892098500626e-15
// 0.1 -2.302585092994045 -2.30258509299405 4.884981308350689e-15
// 1 0 0 0
// 10 2.302585092994046 2.302585092994047 8.881784197001252e-16
// 100 4.605170185988092 4.605170185988079 1.243449787580175e-14
// 1000 6.907755278982137 6.907755278981323 8.135714324453147e-13
// 10000 9.210340371976184 9.210340371907533 6.865086277230148e-11
// 100000 11.51292546497023 11.51292545935356 5.616673348640688e-09
// 1000000 13.81551055796427 13.81551012112039 4.368438872859315e-07
// 10000000 16.11809565095832 16.11806444854419 3.120241413512304e-05
// 100000000 18.42068074395237 18.41880659707298 0.001874146879391247
// 1000000000 20.72326583694641 20.6532968557838 0.06996898116260653
// 10000000000 23.02585092994046 21.30306063168329 1.722790298257163
// 1<xのときはlog(x)=-log(1/x)で計算する
// 収束は速いがsqrtが必要なので桁数が少ないときは効率が悪い
//
public final EFP log () {
return this.log (this);
} //efp.log()
public final EFP log (EFP x) {
int xf = x.flg;
if (xf != 0) { //-x,±0,±Inf,NaN
if (xf << 3 < 0) { //NaN
this.flg = N; //log(NaN)=NaN
} else if (xf << 1 < 0) { //±0
epbFpsr |= EPB_FPSR_DZ;
epbExceptionOperandExponent = xf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = M | I; //log(±0)=-Inf
} else if (xf >= 0) { //+Inf
this.flg = P | I; //log(+Inf)=+Inf
} else { //-x,-Inf
epbFpsr |= EPB_FPSR_OE;
if (xf << 2 < 0) { //log(-Inf)=NaN
epbExceptionOperandExponent = M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //log(-x)=NaN
epbExceptionOperandExponent = M | 0x3fff + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
}
this.flg = N; //log(-x)=NaN, log(-Inf)=NaN
}
return this;
}
//-x,±0,±Inf,NaN以外
if (x.epp == 0 && x.dvl == MSB && x.cvl == 0L) { //+1
this.flg = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //log(1)=±0。RMのときだけ-0
return this;
}
//-x,±0,+1,±Inf,NaN以外
this.inner ();
if (true) {
//1の近くだけlog1p()を使う
if ((x.epp == -1 && x.dvl >>> 32 == 0xffffffff00000000L >>> 32) || //1-2^32<=x<1
(x.epp == 0 && x.dvl >>> 31 == 0x8000000000000000L >>> 31)) { //1<=x<1+2^-32
//return this.inner ().dec (x).outer ().log1p ();
//log(1+x)=x-x^2/2+x^3/3
EFP t = new EFP ().dec (x);
return this.cub (t).div3 ().sub (new EFP ().squ (t).div2 ()).outer ().add (t);
}
}
epbFpsr |= EPB_FPSR_X2; //不正確な結果
EFP v = new EFP (x);
v.epp = v.dvl >= 0xb504f333f9de6484L ? -1 : 0; //SQRT2
int k = x.epp - v.epp; //x=2^k*v, sqrt(2)/2<=v<=sqrt(2)
if (true) { //チェビシェフ展開。[90] 420ns
EFP u = new EFP ().dec (v).div (v.inc ()); //u=(v-1)/(v+1)
v.isqu (u); //u^2
/*
this.imul (LOG_C25, v)
.iadd (LOG_C23).imul (v)
.iadd (LOG_C21).imul (v)
.iadd (LOG_C19).imul (v)
.iadd (LOG_C17).imul (v)
.iadd (LOG_C15).imul (v)
.iadd (LOG_C13).imul (v)
.iadd (LOG_C11).imul (v)
.iadd (LOG_C9).imul (v)
.iadd (LOG_C7).imul (v)
.iadd (LOG_C5).imul (v)
.iadd (LOG_C3).imul (v)
.iadd (LOG_C1).imul (u)
.iadd (v.muli (LOG_2, k)).iadd (v.muli (LOG_2A, k)); //log(x)=log(2^k*v)=k*log(2)+log(v)
*/
this.imul (LOG_C27, v)
.iadd (LOG_C25).imul (v)
.iadd (LOG_C23).imul (v)
.iadd (LOG_C21).imul (v)
.iadd (LOG_C19).imul (v)
.iadd (LOG_C17).imul (v)
.iadd (LOG_C15).imul (v)
.iadd (LOG_C13).imul (v)
.iadd (LOG_C11).imul (v)
.iadd (LOG_C9).imul (v)
.iadd (LOG_C7).imul (v)
.iadd (LOG_C5).imul (v)
.iadd (LOG_C3).imul (v)
.iadd (LOG_C1).imul (u)
.iadd (v.muli (LOG_2, k)).iadd (v.muli (LOG_2A, k)); //log(x)=log(2^k*v)=k*log(2)+log(v)
} else { //expm1を使う。[89] 520ns
EFP vv1 = new EFP ().dec (v);
if (vv1.flg << 1 < 0) { //log(2^k*1)
this.muli (LOG_2, k); //log(2^k)=k*log(2)
} else {
EFP yy = ZERO;
if (-1023 < vv1.epp) {
// Math.log1p(double)を使ってlog(v)の近似値y'を求める
long s = Double.doubleToLongBits (Math.log1p (Double.longBitsToDouble ((long) (vv1.flg | 1023 + vv1.epp << 20) << 32 | vv1.dvl << 1 >>> 12)));
if (s != 0L) {
int sh = (int) (s >>> 32);
yy = new EFP (sh & M, (sh >>> 20 & 2047) - 1023, MSB | s << 12 >>> 1, 0L); //log(v)の近似値y'
}
}
// expm1を使ってlog(v')=y'を満たすv'を求める
vv1.expm1 (yy); //v'-1=expm1(y')
// log(v)=log(v')+log1p((v-v')/v')を使ってlog(v)を計算する
// (v-v')/v'は小さいので1次の項だけ加える
v.dec ().sub (vv1); //(v-1)-(v'-1)=v-v'
this.rcp (vv1.inc ()).imul (v).iadd (yy) //y'+(v-v')/v'≒log(v')+log1p((v-v')/v')=log(v)
.iadd (v.muli (LOG_2, k)).iadd (v.muli (LOG_2A, k)); //log(x)=log(2^k*v)=k*log(2)+log(v)
}
}
return outer ().finish ();
} //efp.log(EFP)
//------------------------------------------------------------------------
//x = x.log10 ()
// x=log10(x)
//y = y.log10 (x)
// y=log10(x)
// 常用対数 common logarithm
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{log($_[0])/log(10)});print$g"
// echo read("../misc/efp.gp");eval("log10(x)=log(x)/log(10)");graph(log10) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | *********
// | | ************* |
// | | ******** |
// +---------+---------+---------+---------+-------******------+---------+---------+
// | | **** |
// | | *** |
// | | ** |
// | |** |
// + +* +
// | |* |
// | ** |
// | * |
// | * |
// + * +
// | * |
// | * |
// | * |
// | * |
// + * +
// | * |
// | * |
// | * |
// | | |
// +---------+---------+---------+---------*---------+---------+---------+---------+
//
// 対数関数との関係
// log10(x)=log(x)/log(10)
//
public final EFP log10 () {
return this.log10 (this);
} //efp.log10()
public final EFP log10 (EFP x) {
//return this.log (x).div (LOG_10); //log(x)/log(10) [90]
int xf = x.flg;
if (xf != 0) { //-x,±0,±Inf,NaN
if (xf << 3 < 0) { //NaN
this.flg = N; //log10(NaN)=NaN
} else if (xf << 1 < 0) { //±0
epbFpsr |= EPB_FPSR_DZ;
epbExceptionOperandExponent = xf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = M | I; //log10(±0)=-Inf
} else if (xf >= 0) { //+Inf
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = P | I; //log10(+Inf)=+Inf
} else { //-x,-Inf
epbFpsr |= EPB_FPSR_OE;
if (xf << 2 < 0) { //-Inf
epbExceptionOperandExponent = M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //-x
epbExceptionOperandExponent = M | 0x3fff + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
}
this.flg = N; //log10(-x)=NaN, log10(-Inf)=NaN
}
return this;
}
//-x,±0,±Inf,NaN以外
int xe = x.epp;
//log10(1)を特別扱いにする
if (xe == 0 && x.dvl == MSB && x.cvl == 0L) { //log10(1)
this.flg = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //log10(1)=±0。RMのときは-0,RN,RZ,RPのときは+0
return this;
}
//log10(10^n)(n>0)を特別扱いにする
if (3 <= xe && xe <= 129) {
EFP t = ACCURATE_LOG10_BASE[xe];
if (t != null && x.dvl == t.dvl && x.cvl == t.cvl) {
//結果は正確だがMC68882に合わせて不正確な結果をセットしておく
epbFpsr |= EPB_FPSR_X2; //不正確な結果
// perl -e "for$e(0..129){$n=($e+1)*617>>11;if($e==int(log(10**$n)/log(2))){print$e,' ';}}"
// 0 3 6 9 13 16 19 23 26 29 33 36 39 43 46 49 53 56 59 63 66 69 73 76 79 83 86 89 93 96 99 102 106 109 112 116 119 122 126 129
return this.seti ((xe + 1) * 617 >> 11);
}
}
//-x,±0,10^n,±Inf,NaN以外
this.inner ();
epbFpsr |= EPB_FPSR_X2; //不正確な結果
EFP v = new EFP (x);
v.epp = v.dvl >= 0xb504f333f9de6484L ? -1 : 0; //SQRT2
int k = x.epp - v.epp; //x=2^k*v, sqrt(2)/2<=v<=sqrt(2)
EFP u = new EFP ().dec (v).div (v.inc ()); //u=(v-1)/(v+1)
v.isqu (u); //u^2
this.imul (LOG10_C27, v)
.iadd (LOG10_C25).imul (v)
.iadd (LOG10_C23).imul (v)
.iadd (LOG10_C21).imul (v)
.iadd (LOG10_C19).imul (v)
.iadd (LOG10_C17).imul (v)
.iadd (LOG10_C15).imul (v)
.iadd (LOG10_C13).imul (v)
.iadd (LOG10_C11).imul (v)
.iadd (LOG10_C9).imul (v)
.iadd (LOG10_C7).imul (v)
.iadd (LOG10_C5).imul (v)
.iadd (LOG10_C3).imul (v)
.iadd (LOG10_C1).imul (u)
.iadd (u.muli (LOG10_2, k));
u.muli (LOG10_2A, k);
return this.outer ().add (u); //log10(x)=log10(2^k*v)=k*log10(2)+log(v) [91]
} //efp.log10()
//------------------------------------------------------------------------
//x = x.log1p ()
// x=log(1+x)
//y = y.log1p (x)
// y=log(1+x)
// 1に近い数の自然対数 natural logarithm of number being close to 1
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{log(1+$_[0])});print$g"
// echo read("../misc/efp.gp");eval("log1p(x)=log(1+x)");graph(log1p) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | ******
// | | ********* |
// | | ******** |
// + + ****** +
// | | ****** |
// | | ***** |
// | | **** |
// | |*** |
// +---------+---------+---------+--------***--------+---------+---------+---------+
// | ***| |
// | ** | |
// | ** | |
// | ** | |
// + ** + +
// | * | |
// | ** | |
// | * | |
// | ** | |
// + * + +
// | * | |
// | * | |
// | * | |
// | * | |
// + ** + +
// | * | |
// | * | |
// | * | |
// | * | |
// +---------+---------+---------*---------+---------+---------+---------+---------+
//
// メモ
// log1p(x)の存在意義は1に極端に近い値の対数をlog(x)よりも正確に求められることだが、
// これは変数xに1に極端に近い値が入っているときlog(x)よりもlog1p(x-1)の方が正確な結果を返すという意味ではない
// 例えば有効桁数が10桁のときxに1.000000001111111111を代入しようとするとxの値は1.000000001になってしまう
// x-1で桁落ちした引数をlog1pに与えたところで結果の精度が高くなるわけがない
// 1に極端に近い値を経由せずにlog1p(1.111111111e-9)を計算すれば正確な結果が得られる
//
// テイラー展開
// log(1+x)=sum[n=1..inf]{(-1)^(n+1)*x^n/n}
//
// チェビシェフ展開
// sqrt(2)/2-1<=x<=sqrt(2)-1
// のとき
// u=x/(x+2)
// x=2*u/(1-u)
// とおくと
// 2*sqrt(2)-3<=u<=3-2*sqrt(2)
// log(x)のときと同じ多項式を使う
//
// メモ
// log1p(-0)=-0,log1p(+0)=+0に注意する
//
public final EFP log1p () {
return this.log1p (this);
} //efp.log1p()
public final EFP log1p (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 3 < 0) { //NaN
this.flg = N; //log1p(NaN)=NaN
} else if (xf << 1 < 0) { //±0
this.flg = xf; //log1p(±0)=±0
} else if (xf >= 0) { //+Inf
this.flg = P | I; //log1p(+Inf)=+Inf
} else { //-Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N; //log1p(-Inf)=NaN
}
return this;
}
//±0,±Inf,NaN以外
if (xf < 0) { //x<0
if (x.epp == 0 && x.dvl == MSB && x.cvl == 0L) { //x==-1
epbFpsr |= EPB_FPSR_DZ; //MC68882はlog1p(-1)でDZをセットする
epbExceptionOperandExponent = M | 0x3fff << 16;
epbExceptionOperandMantissa = 0x8000000000000000L;
this.flg = M | I; //log1p(-1)=-Inf
return this;
} else if (x.epp >= 0) { //x<-1
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = M | 0x3fff + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
this.flg = N; //log1p(x<-1)=NaN
return this;
}
}
epbFpsr |= EPB_FPSR_X2; //不正確な結果
//if (x.epp < -2 || (x.epp == -2 && x.dvl <= (xf < 0 ? 0x95f619980c4336f7L : 0xd413cccfe7799211L))) { //sqrt(2)/2-1<=x<=sqrt(2)-1
if (LOG1P_A.le (x) && x.le (LOG1P_B)) { //sqrt(2)/2-1<=x<=sqrt(2)-1
int savedFpsr = epbFpsr;
this.inner ();
if (this == x) {
x = new EFP (x);
}
EFP u = new EFP ().iadd (x, TWO).rcpdiv (x); //u=x/(x+2)
EFP v = new EFP ().isqu (u); //u^2
/*
return this.imul (LOG_C25, v)
.iadd (LOG_C23).imul (v)
.iadd (LOG_C21).imul (v)
.iadd (LOG_C19).imul (v)
.iadd (LOG_C17).imul (v)
.iadd (LOG_C15).imul (v)
.iadd (LOG_C13).imul (v)
.iadd (LOG_C11).imul (v)
.iadd (LOG_C9).imul (v)
.iadd (LOG_C7).imul (v)
.iadd (LOG_C5).imul (v)
.iadd (LOG_C3).imul (v)
.iadd (LOG_C1).outer ().mul (u);
*/
this.imul (LOG_C27, v)
.iadd (LOG_C25).imul (v)
.iadd (LOG_C23).imul (v)
.iadd (LOG_C21).imul (v)
.iadd (LOG_C19).imul (v)
.iadd (LOG_C17).imul (v)
.iadd (LOG_C15).imul (v)
.iadd (LOG_C13).imul (v)
.iadd (LOG_C11).imul (v)
.iadd (LOG_C9).imul (v)
.iadd (LOG_C7).imul (v)
.iadd (LOG_C5).imul (v)
.iadd (LOG_C3).imul (v)
.iadd (LOG_C1).outer ().mul (u);
return this.originLowerLower (x).correctUnderflow (savedFpsr);
}
return this.inner ().inc (x).outer ().log (); //log(1+x)
} //efp.log1p()
//------------------------------------------------------------------------
//x = x.log2 ()
// x=log2(x)
//y = y.log2 (x)
// y=log2(x)
// 二進対数 binary logarithm
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{log($_[0])/log(2)});print$g"
// echo read("../misc/efp.gp");eval("log2(x)=log(x)/log(2)");graph(log2) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + ****
// | | ****** |
// | | ***** |
// | | **** |
// | | ***** |
// + + *** +
// | | **** |
// | | *** |
// | | *** |
// | | ** |
// +---------+---------+---------+---------+--------***--------+---------+---------+
// | | ** |
// | | ** |
// | | ** |
// | | ** |
// + + * +
// | | ** |
// | | * |
// | | ** |
// | | * |
// + + ** +
// | | * |
// | | * |
// | | * |
// | |** |
// + +* +
// | |* |
// | |* |
// | |* |
// | |* |
// +---------+---------+---------+---------+*--------+---------+---------+---------+
//
// 対数関数との関係
// log2(x)=log(x)/log(2)
//
// チェビシェフ展開
// 指数部を分離する
// log2(x)=log2(2^k*v)=k+log2(v)
// 1<=v<2
// 定義域を0に近付ける
// -(1-t)/(1+t)=(2-t)/(2+t)をtについて解くとt=sqrt(2)
// u=(v-sqrt(2))/(v+sqrt(2))
// 2*sqrt(2)-3<=u<3-2*sqrt(2)
// v=sqrt(2)*(1+u)/(1-u)
// log2(v)=log2(sqrt(2)*(1+u)/(1-u))
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{my($u)=@_;log(sqrt(2)*(1+$u)/(1-$u))/log(2)});print$g"
// +---------+---------+---------+---------+-------*-+---------+---------+---------+
// | | * |
// | | * |
// | | ** |
// | | * |
// + + * +
// | | ** |
// | | * |
// | | * |
// | | ** |
// + + * +
// | | ** |
// | | ** |
// | | * |
// | | ** |
// + +** +
// | |* |
// | ** |
// | ** |
// | *| |
// +---------+---------+---------+-------**+---------+---------+---------+---------+
// | ** | |
// | * | |
// | ** | |
// | ** | |
// + * + +
// | ** | |
// | * | |
// | * | |
// | ** | |
// + * + +
// | * | |
// | ** | |
// | * | |
// | * | |
// + * + +
// | ** | |
// | * | |
// | * | |
// | * | |
// +---------+---------+---------+*--------+---------+---------+---------+---------+
// 奇関数にするためlog2(v)-1/2をチェビシェフ展開する
// echo read("../misc/efp.gp");eval("f(u)=log(sqrt(2)*(1+u)/(1-u))/log(2)-1/2");a=2*sqrt(2)-3;b=3-2*sqrt(2);forstep(n=1,31,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))); | gp -q
// 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31
// 7 14 21 28 35 42 49 56 63 70 77 84 91 98 105 113
//
public final EFP log2 () {
return this.log2 (this);
} //efp.log2()
public final EFP log2 (EFP x) {
//return this.log (x).div (LOG_2); //log(x)/log(2)
int xf = x.flg;
if (xf != 0) { //-x,±0,±Inf,NaN
if (xf << 3 < 0) { //NaN
this.flg = N; //log2(NaN)=NaN
} else if (xf << 1 < 0) { //±0
epbFpsr |= EPB_FPSR_DZ;
epbExceptionOperandExponent = xf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = M | I; //log2(±0)=-Inf
} else if (xf >= 0) { //+Inf
this.flg = P | I; //log2(+Inf)=+Inf
} else { //-x,-Inf
epbFpsr |= EPB_FPSR_OE;
if (xf << 2 < 0) { //-Inf
epbExceptionOperandExponent = M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //-x
epbExceptionOperandExponent = M | 0x3fff + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
}
this.flg = N; //log2(-x)=NaN, log2(-Inf)=NaN
}
return this;
}
//-x,±0,±Inf,NaN以外
//log2(2^n)を特別扱いにする
if (x.dvl == MSB && x.cvl == 0L) { //log2(2^n)
if (x.epp == 0) { //log2(1)
this.flg = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //log2(1)=±0。RMのときは-0,RN,RZ,RPのときは+0
} else { //log2(2^n)(n>0)
//結果は正確だがMC68882に合わせて不正確な結果をセットしておく
epbFpsr |= EPB_FPSR_X2; //不正確な結果
this.seti (x.epp); //log2(2^n)=n
}
return this;
}
//-x,±0,2^n,±Inf,NaN以外
this.inner ();
epbFpsr |= EPB_FPSR_X2; //不正確な結果
EFP v = new EFP (x);
v.epp = v.dvl >= 0xb504f333f9de6484L ? -1 : 0; //SQRT2
int k = x.epp - v.epp; //x=2^k*v, sqrt(2)/2<=v<=sqrt(2)
EFP u = new EFP ().dec (v).div (v.inc ()); //u=(v-1)/(v+1)
v.isqu (u); //u^2
this.imul (LOG2_C27, v)
.iadd (LOG2_C25).imul (v)
.iadd (LOG2_C23).imul (v)
.iadd (LOG2_C21).imul (v)
.iadd (LOG2_C19).imul (v)
.iadd (LOG2_C17).imul (v)
.iadd (LOG2_C15).imul (v)
.iadd (LOG2_C13).imul (v)
.iadd (LOG2_C11).imul (v)
.iadd (LOG2_C9).imul (v)
.iadd (LOG2_C7).imul (v)
.iadd (LOG2_C5).imul (v)
.iadd (LOG2_C3).imul (v)
.iadd (LOG2_C1).imul (u);
u.seti (k);
return this.outer ().add (u); //log2(x)=log2(2^k*v)=k+log2(v)
} //efp.log2()
//------------------------------------------------------------------------
//x = x.lgamma ()
// x=log(Γ(x))
//y = y.lgamma (x)
// y=log(Γ(x))
// ログガンマ関数
//
// グラフ
// echo read("../misc/efp.gp");graph(lngamma) | gp -q
// +---------+---------+---------+---------*---------+---------+---------+---------+
// | * |
// | * |
// | * |
// | * |
// + ** +
// | |* |
// | |* |
// | |* |
// | |* |
// + +* +
// | |** **
// | | * **|
// | | * *** |
// | | ** *** |
// + + ** *** +
// | | * *** |
// | | ** *** |
// | | *** **** |
// | | *** **** |
// +---------+---------+---------+---------+--------*****---******-------+---------+
// | | ***** |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
// 0<x<13のとき
// Γ(x)=Γ(x+1)/x
// log(Γ(x))=log(Γ(x+1))-log(x)
// で13<=xまで持っていく
// log(Γ(12+α))=log(Γ(13+α))-log(12+α)
// log(Γ(11+α))=log(Γ(12+α))-log(11+α)
// =log(Γ(13+α))-log(12+α)-log(11+α)
// =log(Γ(13+α))-log((12+α)*(11+α))
// log(Γ(10+α))=log(Γ(11+α))-log(10+α)
// =log(Γ(13+α))-log((12+α)*(11+α))-log(10+α)
// =log(Γ(13+α))-log((12+α)*(11+α)*(10+α))
// :
// すなわち
// d=1
// while x<13
// d*=x
// x+=1
// としてからlog(Γ(x))を計算してlog(Γ(x))-log(d)を返す
//
// 13<=xのとき
// log(Γ(x))=(x-1/2)*log(x)-x+log(2*π)/2+Σ[n=1..∞]{B(2*n)/(2*n*(2*n-1)*x^(2*n-1))]
//
public final EFP lgamma () {
return this.lgamma (this);
} //efp.lgamma()
public final EFP lgamma (EFP x) {
int xf = x.flg;
if (xf != 0) { //-x,±0,±Inf,NaN
this.flg = (xf == (P | Z) || xf == (P | I) ? P | I : //lgamma(+0)=lgamma(+Inf)=+Inf
N); //lgamma(NaN)=lgamma(-Inf)=lgamma(-x)=lgamma(-0)=NaN
return this;
}
//+x
this.inner ();
x = new EFP (x);
EFP d = null;
if (x.lt (THIRTEEN)) {
d = new EFP (ONE);
do {
d.mul (x);
x.inc ();
} while (x.lt (THIRTEEN));
}
EFP t = new EFP ().rcp (x); //1/x
EFP t2 = new EFP ().squ (t); //1/x^2
this.mul (LGAMMA_C14, t2)
.add (LGAMMA_C13).mul (t2)
.add (LGAMMA_C12).mul (t2)
.add (LGAMMA_C11).mul (t2)
.add (LGAMMA_C10).mul (t2)
.add (LGAMMA_C9).mul (t2)
.add (LGAMMA_C8).mul (t2)
.add (LGAMMA_C7).mul (t2)
.add (LGAMMA_C6).mul (t2)
.add (LGAMMA_C5).mul (t2)
.add (LGAMMA_C4).mul (t2)
.add (LGAMMA_C3).mul (t2)
.add (LGAMMA_C2).mul (t2)
.add (LGAMMA_C1).mul (t)
.add (LOGTWOPI_2).sub (x); //-x+log(2*π)/2+Σ[n=1..14]{B(2*n)/(2*n*(2*n-1)*x^(2*n-1))]
t.sub (x, ONE_2); //x-1/2
this.add (x.log ().mul (t)); //(x-1/2)*log(x)-x+log(2*π)/2+Σ[n=1..14]{B(2*n)/(2*n*(2*n-1)*x^(2*n-1))]
if (d != null) {
this.sub (d.log ()); //log(Γ(x))-log(d)
}
return this.outer ().finish ();
} //efp.lgamma(EFP)
//------------------------------------------------------------------------
//b = x.lt (y)
// b=x<y
// より小さいか
//
// -Inf==-Inf<-x<-0==+0<+x<+Inf==+Inf
//
// NaNの扱い
// どちらかがNaNのときはfalseを返す
//
public boolean lt (EFP y) {
int xf = this.flg;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
return EFP_LT_TABLE[xf >>> 28] << (yf >>> 28 - 1) < 0;
}
//両方±0,±Inf,NaN以外
if (xf != yf) { //両方±0,±Inf,NaN以外で符号が違う
return xf < yf;
}
//両方±0,±Inf,NaN以外で符号が同じ
int s;
long t;
return (xf >= 0 ? 1 : -1) * ((s = this.epp - y.epp) != 0 ? s >= 0 ? 1 : -1 :
(t = this.dvl - y.dvl) != 0L ? t >= 0L ? 1 : -1 :
(t = (this.cvl >>> 1) - (y.cvl >>> 1)) != 0L ? t >= 0L ? 1 : -1 :
0) < 0;
} //efp.lt(EFP)
//------------------------------------------------------------------------
//x = x.max (y)
// x=max(x,y)
//z = z.max (x, y)
// z=max(x,y)
// 最大値
//
// どちらかがNaNのときはNaN
// -0<+0とみなされる
//
public final EFP max (EFP y) {
return this.max (this, y);
} //efp.max(EFP)
public final EFP max (EFP x, EFP y) {
if ((x.flg | y.flg) << 3 < 0) { //どちらかがNaN
this.flg = N; //NaN
} else if (x.compareTo (y) >= 0) { //両方NaN以外でx>=y。cmpは-0>=+0なので不可
this.flg = x.flg; //x
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
} else { //両方NaN以外でx<y
this.flg = y.flg; //y
this.epp = y.epp;
this.dvl = y.dvl;
this.cvl = y.cvl;
}
return this;
} //efp.max(EFP)
//------------------------------------------------------------------------
//x = x.min (y)
// x=min(x,y)
//z = z.min (x, y)
// z=min(x,y)
// 最小値
//
// どちらかがNaNのときはNaN
// -0<+0とみなされる
//
public final EFP min (EFP y) {
return this.min (this, y);
} //efp.min(EFP)
public final EFP min (EFP x, EFP y) {
if ((x.flg | y.flg) << 3 < 0) { //どちらかがNaN
this.flg = N; //NaN
} else if (x.compareTo (y) <= 0) { //両方NaN以外でx<=y。cmpは+0<=-0なので不可
this.flg = x.flg; //x
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
} else { //両方NaN以外でx<y
this.flg = y.flg; //y
this.epp = y.epp;
this.dvl = y.dvl;
this.cvl = y.cvl;
}
return this;
} //efp.min(EFP)
//------------------------------------------------------------------------
//x = x.mul (y)
// x*=y
//z = z.mul (x, y)
// z=x*y
// 乗算
//
// (xn/xd)*(yn/yd)
// =(xn*yn)/(xd*yd)
//
// 分割統治法による多倍長乗算
// 2分割
// (a*x+b)*(c*x+d) = a*c*x^2+(a*d+b*c)*x+b*d
// (1) (2) (3) (4)
// = a*c*(x^2+x)+b*d*(x+1)-(a-b)*(c-d)*x
// (1) (2) (3)
// (3)の積は(a,b),(c,d)の大小関係によって加える場合と引く場合がある
// 桁数を2倍にしたとき乗算のコストが3倍になる
// 桁数n=2^kのときのコストは3^k=3^log2(n)=n^log2(3)≒n^1.585
// 3分割
// (a*x^2+b*x+c)*(d*x^2+e*x+f) = a*d*x^4+(a*e+b*d)*x^3+(a*f+b*e+c*d)*x^2+(b*f+c*e)*x+c*f
// (1) (2) (3) (4) (5) (6) (7) (8) (9)
// = a*d*(x^4+x^3+x^2)+b*e*(x^3+x^2+x)+c*f*(x^2+x+1)-(a-b)*(d-e)*x^3-(a-c)*(d-f)*x^2-(b-c)*(e-f)*x
// (1) (2) (3) (4) (5) (6)
// (4),(5),(6)の積は(a,b,c),(d,e,f)の大小関係によって加える場合と引く場合がある
// 桁数を3倍にしたとき乗算のコストが6倍になる
// 桁数n=3^kのときのコストは6^k=6^log3(n)=n^log3(6)≒n^1.631
// 分割統治法による多倍長乗算では3分割よりも2分割の方が効率が良い
//
// 32bit,30bit,30bitに分割する場合
// x^6 x^5 x^4 x^3 x^2 x^1 x^0
// +---------------+-------------+-------------+
// | a*d | c*f | c*f |
// +---------------+-------------+-------------+
// +---------------+-------------+
// | a*d | c*f |
// +---------------+-------------+
// +---------------+
// | a*d |
// +---------------+
// +-------------+-------------+
// | b*e | b*e |
// +-------------+-------------+
// +-------------+
// | b*e |
// +-------------+
// +---------------+-------------+
// | -(a-b)*(d-e) |-(b-c)*(e-f) |
// +---------------+-------------+
// +---------------+
// | -(a-c)*(d-f) |
// +---------------+
// x^6 x^5 x^4 x^3 x^2 x^1 x^0
//
public final EFP mul (EFP y) {
int xf = this.flg;
int yf = y.flg;
{
int o;
if ((o = xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if (o << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
} else if ((o &= (Z | I)) == (Z | I)) { //±0*±InfのときNaN
epbFpsr |= EPB_FPSR_OE;
if (yf << 1 < 0) { //±Inf*±0
epbExceptionOperandExponent = yf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //±0*±Inf
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
}
this.flg = N;
} else { //両方±0,NaN以外でどちらかが±Infのとき±Inf、両方±Inf,NaN以外でどちらかが±0のとき±0
this.flg = (xf ^ yf) & M | o;
}
return this;
}
}
//符号
int zf = xf ^ yf; //符号が同じならばP、異なればM。ここでセットされるのはMだけ
//指数部
int ze = this.epp + y.epp;
//以下はLEN<=92bitでなければならない
//掛ける
// 92bitの仮数部を32bit,30bit,30bitに3分割する
// 111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
// x.dvl HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
// x.cvl LLLLLLLLLLLLLLLLLLLLLLLLLLLL000000000000000000000000000000000000
long xh = this.dvl; // xh HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
long yh = y.dvl;
long xl = (xh << -2 | this.cvl >>> 2) >>> -30; //xh<<-2 LL00000000000000000000000000000000000000000000000000000000000000
// x.cvl>>>2 00LLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xh<<-2|x.cvl>>>2 LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xl 0000000000000000000000000000000000LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
long yl = (yh << -2 | y.cvl >>> 2) >>> -30;
long xm = xh << 32 >>> -30; // xh<<32 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL00000000000000000000000000000000
// xm 0000000000000000000000000000000000MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
long ym = yh << 32 >>> -30;
xh >>>= 32; // xh 00000000000000000000000000000000HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
yh >>>= 32;
// xh xm xl
// * yh ym yl
// -----------------
// xl*yl
// xl*ym
// yl*xm
// xl*yh
// yl*xh
// xm*ym
// xm*yh
// ym*xh
// xh*yh
// -----------------
// zd zc zb
long zb = xl * yl; //60bit
long zc = xl * yh + yl * xh + xm * ym; //62bit*2+60bit
long zd = xh * yh; //64bit
xl *= ym; //xl*ym。60bit
yl *= xm; //yl*xm。60bit
xm *= yh; //xm*yh。62bit
ym *= xh; //ym*xh。62bit
zb += (xl << -30 >>> 4) + (yl << -30 >>> 4); //xl*ymの下位30bit<<30,yl*xmの下位30bit<<30。60bit*3
zc += (xm << -30 >>> 4) + (ym << -30 >>> 4); //xm*yhの下位30bit<<30,ym*xhの下位30bit<<30。62bit*2+60bit*3
zc += (xl >>> 30) + (yl >>> 30) + (zb >>> -4); //xl*ymの上位30bit,yl*xmの上位30bit,zbからのキャリー4bit。62bit*2+60bit*3+30bit*2+4bitで64bitに収まる
zd += (xm >>> 30) + (ym >>> 30) + (zc >>> -4); //xm*yhの上位32bit,ym*xhの上位32bit,zcからのキャリー4bit。積は92*2=184bitで64bit,60bit,60bitに収まる
zb <<= 4; //sticky bitにゴミが残っていると困るので使用済みのキャリーを押し出す
zc <<= 4; //使用済みのキャリーを押し出してzdとzcの隙間を詰める。zcの下位4bitに隙間ができるがsticky bitなのでzbを詰める必要はない
//正規化する
// zdのMSBに隙間がないときは整数部が1+1=2bitになっているので指数部を1増やす
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.finish2 (zf, ze, zd, zc, zb);
} //efp.mul(EFP)
public final EFP imul (EFP y) {
int xf = this.flg;
int yf = y.flg;
{
int o;
if ((o = xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if (o << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
} else if ((o &= (Z | I)) == (Z | I)) { //±0*±InfのときNaN
epbFpsr |= EPB_FPSR_OE;
if (yf << 1 < 0) { //±Inf*±0
epbExceptionOperandExponent = yf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //±0*±Inf
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
}
this.flg = N;
} else { //両方±0,NaN以外でどちらかが±Infのとき±Inf、両方±Inf,NaN以外でどちらかが±0のとき±0
this.flg = (xf ^ yf) & M | o;
}
return this;
}
}
//符号
int zf = xf ^ yf; //符号が同じならばP、異なればM。ここでセットされるのはMだけ
//指数部
int ze = this.epp + y.epp;
//以下はLEN<=92bitでなければならない
//掛ける
// 92bitの仮数部を32bit,30bit,30bitに3分割する
// 111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
// x.dvl HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
// x.cvl LLLLLLLLLLLLLLLLLLLLLLLLLLLL000000000000000000000000000000000000
long xh = this.dvl; // xh HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
long yh = y.dvl;
long xl = (xh << -2 | this.cvl >>> 2) >>> -30; //xh<<-2 LL00000000000000000000000000000000000000000000000000000000000000
// x.cvl>>>2 00LLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xh<<-2|x.cvl>>>2 LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xl 0000000000000000000000000000000000LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
long yl = (yh << -2 | y.cvl >>> 2) >>> -30;
long xm = xh << 32 >>> -30; // xh<<32 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL00000000000000000000000000000000
// xm 0000000000000000000000000000000000MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
long ym = yh << 32 >>> -30;
xh >>>= 32; // xh 00000000000000000000000000000000HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
yh >>>= 32;
// xh xm xl
// * yh ym yl
// -----------------
// xl*yl
// xl*ym
// yl*xm
// xl*yh
// yl*xh
// xm*ym
// xm*yh
// ym*xh
// xh*yh
// -----------------
// zd zc zb
long zb = xl * yl; //60bit
long zc = xl * yh + yl * xh + xm * ym; //62bit*2+60bit
long zd = xh * yh; //64bit
xl *= ym; //xl*ym。60bit
yl *= xm; //yl*xm。60bit
xm *= yh; //xm*yh。62bit
ym *= xh; //ym*xh。62bit
zb += (xl << -30 >>> 4) + (yl << -30 >>> 4); //xl*ymの下位30bit<<30,yl*xmの下位30bit<<30。60bit*3
zc += (xm << -30 >>> 4) + (ym << -30 >>> 4); //xm*yhの下位30bit<<30,ym*xhの下位30bit<<30。62bit*2+60bit*3
zc += (xl >>> 30) + (yl >>> 30) + (zb >>> -4); //xl*ymの上位30bit,yl*xmの上位30bit,zbからのキャリー4bit。62bit*2+60bit*3+30bit*2+4bitで64bitに収まる
zd += (xm >>> 30) + (ym >>> 30) + (zc >>> -4); //xm*yhの上位32bit,ym*xhの上位32bit,zcからのキャリー4bit。積は92*2=184bitで64bit,60bit,60bitに収まる
zb <<= 4; //sticky bitにゴミが残っていると困るので使用済みのキャリーを押し出す
zc <<= 4; //使用済みのキャリーを押し出してzdとzcの隙間を詰める。zcの下位4bitに隙間ができるがsticky bitなのでzbを詰める必要はない
//正規化する
// zdのMSBに隙間がないときは整数部が1+1=2bitになっているので指数部を1増やす
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.ifinish (zf, ze, zd, zc, zb);
} //efp.imul(EFP)
public final EFP mul (EFP x, EFP y) { //11.7
int xf = x.flg;
int yf = y.flg;
{
int o;
if ((o = xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if (o << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
} else if ((o &= (Z | I)) == (Z | I)) { //±0*±InfのときNaN
epbFpsr |= EPB_FPSR_OE;
if (yf << 1 < 0) { //±Inf*±0
epbExceptionOperandExponent = yf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //±0*±Inf
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
}
this.flg = N;
} else { //両方±0,NaN以外でどちらかが±Infのとき±Inf、両方±Inf,NaN以外でどちらかが±0のとき±0
this.flg = (xf ^ yf) & M | o;
}
return this;
}
}
//符号
int zf = xf ^ yf; //符号が同じならばP、異なればM。ここでセットされるのはMだけ
//指数部
int ze = x.epp + y.epp;
//以下はLEN<=92bitでなければならない
//掛ける
// 92bitの仮数部を32bit,30bit,30bitに3分割する
// 111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
// x.dvl HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
// x.cvl LLLLLLLLLLLLLLLLLLLLLLLLLLLL000000000000000000000000000000000000
long xh = x.dvl; // xh HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
long yh = y.dvl;
long xl = (xh << -2 | x.cvl >>> 2) >>> -30; // xh<<-2 LL00000000000000000000000000000000000000000000000000000000000000
// x.cvl>>>2 00LLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xh<<-2|x.cvl>>>2 LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xl 0000000000000000000000000000000000LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
long yl = (yh << -2 | y.cvl >>> 2) >>> -30;
long xm = xh << 32 >>> -30; // xh<<32 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL00000000000000000000000000000000
// xm 0000000000000000000000000000000000MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
long ym = yh << 32 >>> -30;
xh >>>= 32; // xh 00000000000000000000000000000000HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
yh >>>= 32;
// xh xm xl
// * yh ym yl
// -----------------
// xl*yl
// xl*ym
// yl*xm
// xl*yh
// yl*xh
// xm*ym
// xm*yh
// ym*xh
// xh*yh
// -----------------
// zd zc zb
long zb = xl * yl; //60bit
long zc = xl * yh + yl * xh + xm * ym; //62bit*2+60bit
long zd = xh * yh; //64bit
xl *= ym; //xl*ym。60bit
yl *= xm; //yl*xm。60bit
xm *= yh; //xm*yh。62bit
ym *= xh; //ym*xh。62bit
zb += (xl << -30 >>> 4) + (yl << -30 >>> 4); //xl*ymの下位30bit<<30,yl*xmの下位30bit<<30。60bit*3
zc += (xm << -30 >>> 4) + (ym << -30 >>> 4); //xm*yhの下位30bit<<30,ym*xhの下位30bit<<30。62bit*2+60bit*3
zc += (xl >>> 30) + (yl >>> 30) + (zb >>> -4); //xl*ymの上位30bit,yl*xmの上位30bit,zbからのキャリー4bit。62bit*2+60bit*3+30bit*2+4bitで64bitに収まる
zd += (xm >>> 30) + (ym >>> 30) + (zc >>> -4); //xm*yhの上位32bit,ym*xhの上位32bit,zcからのキャリー4bit。積は92*2=184bitで64bit,60bit,60bitに収まる
zb <<= 4; //sticky bitにゴミが残っていると困るので使用済みのキャリーを押し出す
zc <<= 4; //使用済みのキャリーを押し出してzdとzcの隙間を詰める。zcの下位4bitに隙間ができるがsticky bitなのでzbを詰める必要はない
//正規化する
// zdのMSBに隙間がないときは整数部が1+1=2bitになっているので指数部を1増やす
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.finish2 (zf, ze, zd, zc, zb);
} //efp.mul(EFP,EFP)
public final EFP imul (EFP x, EFP y) { //11.7
int xf = x.flg;
int yf = y.flg;
{
int o;
if ((o = xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if (o << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
} else if ((o &= (Z | I)) == (Z | I)) { //±0*±InfのときNaN
epbFpsr |= EPB_FPSR_OE;
if (yf << 1 < 0) { //±Inf*±0
epbExceptionOperandExponent = yf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //±0*±Inf
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
}
this.flg = N;
} else { //両方±0,NaN以外でどちらかが±Infのとき±Inf、両方±Inf,NaN以外でどちらかが±0のとき±0
this.flg = (xf ^ yf) & M | o;
}
return this;
}
}
//符号
int zf = xf ^ yf; //符号が同じならばP、異なればM。ここでセットされるのはMだけ
//指数部
int ze = x.epp + y.epp;
//以下はLEN<=92bitでなければならない
//掛ける
// 92bitの仮数部を32bit,30bit,30bitに3分割する
// 111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
// x.dvl HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
// x.cvl LLLLLLLLLLLLLLLLLLLLLLLLLLLL000000000000000000000000000000000000
long xh = x.dvl; // xh HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
long yh = y.dvl;
long xl = (xh << -2 | x.cvl >>> 2) >>> -30; // xh<<-2 LL00000000000000000000000000000000000000000000000000000000000000
// x.cvl>>>2 00LLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xh<<-2|x.cvl>>>2 LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xl 0000000000000000000000000000000000LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
long yl = (yh << -2 | y.cvl >>> 2) >>> -30;
long xm = xh << 32 >>> -30; // xh<<32 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL00000000000000000000000000000000
// xm 0000000000000000000000000000000000MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
long ym = yh << 32 >>> -30;
xh >>>= 32; // xh 00000000000000000000000000000000HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
yh >>>= 32;
// xh xm xl
// * yh ym yl
// -----------------
// xl*yl
// xl*ym
// yl*xm
// xl*yh
// yl*xh
// xm*ym
// xm*yh
// ym*xh
// xh*yh
// -----------------
// zd zc zb
long zb = xl * yl; //60bit
long zc = xl * yh + yl * xh + xm * ym; //62bit*2+60bit
long zd = xh * yh; //64bit
xl *= ym; //xl*ym。60bit
yl *= xm; //yl*xm。60bit
xm *= yh; //xm*yh。62bit
ym *= xh; //ym*xh。62bit
zb += (xl << -30 >>> 4) + (yl << -30 >>> 4); //xl*ymの下位30bit<<30,yl*xmの下位30bit<<30。60bit*3
zc += (xm << -30 >>> 4) + (ym << -30 >>> 4); //xm*yhの下位30bit<<30,ym*xhの下位30bit<<30。62bit*2+60bit*3
zc += (xl >>> 30) + (yl >>> 30) + (zb >>> -4); //xl*ymの上位30bit,yl*xmの上位30bit,zbからのキャリー4bit。62bit*2+60bit*3+30bit*2+4bitで64bitに収まる
zd += (xm >>> 30) + (ym >>> 30) + (zc >>> -4); //xm*yhの上位32bit,ym*xhの上位32bit,zcからのキャリー4bit。積は92*2=184bitで64bit,60bit,60bitに収まる
zb <<= 4; //sticky bitにゴミが残っていると困るので使用済みのキャリーを押し出す
zc <<= 4; //使用済みのキャリーを押し出してzdとzcの隙間を詰める。zcの下位4bitに隙間ができるがsticky bitなのでzbを詰める必要はない
//正規化する
// zdのMSBに隙間がないときは整数部が1+1=2bitになっているので指数部を1増やす
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.ifinish (zf, ze, zd, zc, zb);
} //efp.imul(EFP,EFP)
//------------------------------------------------------------------------
//x = x.mul2 ()
// x*=2
//y = y.mul2 (x)
// y=x*2
// 2倍
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{2*$_[0]});print$g"
// +---------+---------+---------+---------+---------+---------**--------+---------+
// | | ** |
// | | ** |
// | | ** |
// | | ** |
// + + ** +
// | | ** |
// | | ** |
// | | ** |
// | | ** |
// + + ** +
// | | ** |
// | | ** |
// | | ** |
// | | ** |
// + + ** +
// | | ** |
// | | ** |
// | | ** |
// | |** |
// +---------+---------+---------+---------**--------+---------+---------+---------+
// | ** |
// | **| |
// | ** | |
// | ** | |
// + ** + +
// | ** | |
// | ** | |
// | ** | |
// | ** | |
// + ** + +
// | ** | |
// | ** | |
// | ** | |
// | ** | |
// + ** + +
// | ** | |
// | ** | |
// | ** | |
// | ** | |
// +---------+---------**--------+---------+---------+---------+---------+---------+
// echo read("../misc/efp.gp");eval("mul2(x)=x*2");graph(mul2) | gp -q
// +---------+---------+---------+---------+---------+---------*---------+---------+
// | | * |
// | | * |
// | | * |
// | | * |
// + + * +
// | | * |
// | | * |
// | | * |
// | | * |
// + + * +
// | | * |
// | | * |
// | | * |
// | | * |
// + + * +
// | | * |
// | | * |
// | | * |
// | |* |
// +---------+---------+---------+---------*---------+---------+---------+---------+
// | *| |
// | * | |
// | * | |
// | * | |
// + * + +
// | * | |
// | * | |
// | * | |
// | * | |
// + * + +
// | * | |
// | * | |
// | * | |
// | * | |
// + * + +
// | * | |
// | * | |
// | * | |
// | * | |
// +---------+---------*---------+---------+---------+---------+---------+---------+
//
public final EFP mul2 () {
return this.finish (this.flg, this.epp + 1, this.dvl, this.cvl, 0L);
} //efp.mul2()
public final EFP imul2 () {
this.epp++;
return this;
} //efp.imul2()
public final EFP mul2 (EFP x) {
return this.finish (x.flg, x.epp + 1, x.dvl, x.cvl, 0L);
} //efp.mul2(EFP)
public final EFP imul2 (EFP x) {
this.flg = x.flg;
this.epp = x.epp + 1;
this.dvl = x.dvl;
this.cvl = x.cvl;
return this;
} //efp.imul2(EFP)
//------------------------------------------------------------------------
//x = x.mul3 ()
// x*=3
//y = y.mul3 (x)
// y=x*3
// 3倍
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{3*$_[0]});print$g"
// echo read("../misc/efp.gp");eval("mul3(x)=x*3");graph(mul3) | gp -q
// +---------+---------+---------+---------+---------+--**-----+---------+---------+
// | | ** |
// | | * |
// | | ** |
// | | ** |
// + + * +
// | | ** |
// | | ** |
// | | * |
// | | ** |
// + + ** +
// | | * |
// | | ** |
// | | ** |
// | | * |
// + + ** +
// | | ** |
// | | * |
// | |** |
// | ** |
// +---------+---------+---------+---------*---------+---------+---------+---------+
// | ** |
// | **| |
// | * | |
// | ** | |
// + ** + +
// | * | |
// | ** | |
// | ** | |
// | * | |
// + ** + +
// | ** | |
// | * | |
// | ** | |
// | ** | |
// + * + +
// | ** | |
// | ** | |
// | * | |
// | ** | |
// +---------+---------+-----**--+---------+---------+---------+---------+---------+
//
public final EFP mul3 () {
return this.muli (this, 3);
} //efp.mul3()
public final EFP mul3 (EFP x) {
//return this.muli (x, 3); //x*3
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int ze = x.epp + 1;
long zd = x.dvl;
long zc = x.cvl;
long t = zc;
zc += (zc >>> 1); //bit63が1→0のときcから溢れている
zd += (zd >>> 1) + ((zc & ~t) >>> -1); //bit63が1→0のときdから溢れている
if (zd >= 0L) { //2bit増えた
zc = zd << -1 | zc >>> 1;
zd = MSB | zd >>> 1;
ze++;
}
return this.finish (xf, ze, zd, zc, 0L);
} //efp.mul3(EFP)
//------------------------------------------------------------------------
//x = x.muli (n)
// x*=n
//z = z.muli (x, n)
// z=x*n
// int乗算
//
public final EFP muli (int n) {
return this.muli (this, n);
} //efp.muli(int)
public final EFP muli (EFP x, int n) {
//return this.mul (x, new EFP (n)); //x*n
int xf = x.flg;
if (n == 0) { //0倍
this.flg = (xf & (I | N)) != 0 ? N : xf | Z; //±Inf*0=NaN, NaN*0=NaN, ±0*0=±0, ±x*0=±0
return this;
}
if (xf << 1 != 0) { //xが±0,±Inf,NaN
this.flg = xf << 3 < 0 ? N : xf ^ (n & M); //NaN*±n=NaN, ±Inf*±n=±Inf, ±0*±n=±0
return this;
}
//両方±0,±Inf,NaN以外
int ze = x.epp;
long zd = x.dvl;
long zc = x.cvl;
if (n < 0) { //乗数が負
xf ^= M;
if (n == 0x80000000) {
ze += 31;
if ((short) ze != ze) { //オーバーフロー
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = zd;
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±Inf
}
this.flg = xf;
this.epp = ze;
this.dvl = zd;
this.cvl = zc;
return this;
}
n = -n;
}
if (n > 1) {
long y = (long) n; //0x80000000は処理済みなので0xffffffffLでマスクする必要はない
//掛ける
// x0 x1 x2
// * y0
// -----------
// x2*y0
// x1*y0
// x0*y0
// -----------
// zd zc
zc = (zc >>> 32) * y;
long t = (zd & 0xffffffffL) * y + (zc >>> 32);
zc = t << 32 | (zc & 0xffffffffL);
zd = (zd >>> 32) * y + (t >>> 32);
//正規化する
int o = Long.numberOfLeadingZeros (zd);
ze += 32 - o;
if (o > 0) {
zd = zd << o | zc >>> -o;
zc <<= o;
}
}
return this.finish (xf, ze, zd, zc, 0L);
} //efp.muli(EFP,int)
//------------------------------------------------------------------------
//x = x.mulpi ()
// x*=pi
//y = y.mulpi (x)
// y=x*pi
// 円周率倍
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{4*atan2(1,1)*$_[0]});print$g"
// echo read("../misc/efp.gp");eval("mulpi(x)=x*Pi");graph(mulpi) | gp -q
// +---------+---------+---------+---------+---------+-**------+---------+---------+
// | | * |
// | | ** |
// | | * |
// | | ** |
// + + ** +
// | | * |
// | | ** |
// | | ** |
// | | * |
// + + ** +
// | | ** |
// | | * |
// | | ** |
// | | * |
// + + ** +
// | | ** |
// | | * |
// | |** |
// | ** |
// +---------+---------+---------+---------*---------+---------+---------+---------+
// | ** |
// | **| |
// | * | |
// | ** | |
// + ** + +
// | * | |
// | ** | |
// | * | |
// | ** | |
// + ** + +
// | * | |
// | ** | |
// | ** | |
// | * | |
// + ** + +
// | ** | |
// | * | |
// | ** | |
// | * | |
// +---------+---------+------**-+---------+---------+---------+---------+---------+
//
public final EFP mulpi () {
return this.mul (this, PI);
} //efp.mulpi()
public final EFP mulpi (EFP x) {
return this.mul (x, PI); //x*pi
} //efp.mulpi(EFP)
//------------------------------------------------------------------------
//z = z.imulw (w, x, y)
// z+w=x*y
// 倍精度乗算
// zはz.imul(x,y)の結果と等しい
// zはnearest-evenで丸められる
// wの符号はzの符号と同じとは限らない
// wの絶対値はulp(z)/2以下
// 結果は常に正確
//
public final EFP imulw (EFP w, EFP x, EFP y) {
int xf = x.flg;
int yf = y.flg;
{
int o;
if ((o = xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if (o << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
} else if ((o &= (Z | I)) == (Z | I)) { //±0*±InfのときNaN
epbFpsr |= EPB_FPSR_OE;
if (yf << 1 < 0) { //±Inf*±0
epbExceptionOperandExponent = yf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //±0*±Inf
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
}
this.flg = N;
} else { //両方±0,NaN以外でどちらかが±Infのとき±Inf、両方±Inf,NaN以外でどちらかが±0のとき±0
this.flg = (xf ^ yf) & M | o;
}
w.flg = this.flg; //zが±0,±Inf,NaNのときwも±0,±Inf,NaN
return this;
}
}
//符号
int zf = xf ^ yf; //符号が同じならばP、異なればM。ここでセットされるのはMだけ
//指数部
int ze = x.epp + y.epp;
//以下はLEN<=92bitでなければならない
//掛ける
// 92bitの仮数部を32bit,30bit,30bitに3分割する
// 111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
// x.dvl HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
// x.cvl LLLLLLLLLLLLLLLLLLLLLLLLLLLL000000000000000000000000000000000000
long xh = x.dvl; // xh HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL
long yh = y.dvl;
long xl = (xh << -2 | x.cvl >>> 2) >>> -30; // xh<<-2 LL00000000000000000000000000000000000000000000000000000000000000
// x.cvl>>>2 00LLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xh<<-2|x.cvl>>>2 LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL0000000000000000000000000000000000
// xl 0000000000000000000000000000000000LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
long yl = (yh << -2 | y.cvl >>> 2) >>> -30;
long xm = xh << 32 >>> -30; // xh<<32 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL00000000000000000000000000000000
// xm 0000000000000000000000000000000000MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
long ym = yh << 32 >>> -30;
xh >>>= 32; // xh 00000000000000000000000000000000HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
yh >>>= 32;
// xh xm xl
// * yh ym yl
// -----------------
// xl*yl
// xl*ym
// yl*xm
// xl*yh
// yl*xh
// xm*ym
// xm*yh
// ym*xh
// xh*yh
// -----------------
// zd zc zb
long zb = xl * yl; //60bit
long zc = xl * yh + yl * xh + xm * ym; //62bit*2+60bit
long zd = xh * yh; //64bit
xl *= ym; //xl*ym。60bit
yl *= xm; //yl*xm。60bit
xm *= yh; //xm*yh。62bit
ym *= xh; //ym*xh。62bit
zb += (xl << -30 >>> 4) + (yl << -30 >>> 4); //xl*ymの下位30bit<<30,yl*xmの下位30bit<<30。60bit*3
zc += (xm << -30 >>> 4) + (ym << -30 >>> 4); //xm*yhの下位30bit<<30,ym*xhの下位30bit<<30。62bit*2+60bit*3
zc += (xl >>> 30) + (yl >>> 30) + (zb >>> -4); //xl*ymの上位30bit,yl*xmの上位30bit,zbからのキャリー4bit。62bit*2+60bit*3+30bit*2+4bitで64bitに収まる
zd += (xm >>> 30) + (ym >>> 30) + (zc >>> -4); //xm*yhの上位32bit,ym*xhの上位32bit,zcからのキャリー4bit。積は92*2=184bitで64bit,60bit,60bitに収まる
zb <<= 4; //使用済みのキャリーを押し出す
zc = zc << 4 | zb >>> -4; //使用済みのキャリーを押し出してzbから4bit持ってくる
zb <<= 4;
//上位を正規化する
// zdのMSBに隙間がないときは整数部が1+1=2bitになっているので指数部を1増やす
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc = zc << 1 | zb >>> -1;
zb <<= 1;
}
//積を上位と下位に分ける
// 111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
// zd HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// zc hhhhhhhhhhhhhhhhhhhhhhhhhhhhLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
// zb llllllllllllllllllllllllllllllllllllllllllllllllllllllll00000000
// zd HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// zc hhhhhhhhhhhhhhhhhhhhhhhhhhhh000000000000000000000000000000000000
// wd LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLllllllllllllllllllllllllllll
// wc llllllllllllllllllllllllllll000000000000000000000000000000000000
int wf = zf;
int we = ze - LEN;
long wd = zc << LEN - 64 | zb >>> -(LEN - 64);
long wc = zb << LEN - 64;
zc &= -LSB;
//zb = 0L;
//下位の絶対値を上位の1/2ulp以下にする
if (wd < 0L && (zc & LSB | wd << 1 | wc) != 0L) { //guard bitが1かつLSBとround bitとsticky bitのいずれかが0でない
//下位からLSBを引く(LSBから下位を引いて符号を反転する)
wf ^= M;
wc = -(wc >>> 1);
wd = -wd - (wc >>> -1);
wc <<= 1;
//上位にLSBを加える
if ((zc += LSB) == 0L && ++zd == 0L) { //LSBを加えて、溢れたとき
zd = MSB; //MSBだけセットして
ze++; //指数部を1増やす
}
}
//下位を正規化する
if (wd >= 0L) { //正規化が必要
if (wd != 0L) {
int o = Long.numberOfLeadingZeros (wd); //1以上
we -= o;
wd = wd << o | wc >>> -o; //o==0は不可
wc <<= o;
} else if (wc != 0L) {
int o = Long.numberOfLeadingZeros (wc); //0以上
we -= 64 + o;
wd = wc << o;
wc = 0L;
} else {
wf |= Z;
}
}
//結果
if (ze > 32767) { //オーバーフロー
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = zf;
epbExceptionOperandMantissa = zd;
return this.sete (w.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | zf >>> 31])); //±Inf
} else if (ze < -32768 || wf << 1 >= 0 && we < -32768) { //アンダーフロー
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = zf;
epbExceptionOperandMantissa = zd;
return this.sete (w.sete (UNFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | zf >>> 31])); //±0
} else {
this.flg = zf;
this.epp = ze;
this.dvl = zd;
this.cvl = zc;
w.flg = wf;
w.epp = we;
w.dvl = wd;
w.cvl = wc;
return this;
}
} //efp.imulw(EFP,EFP,EFP)
//------------------------------------------------------------------------
//b = x.ne (y)
// b=x!=y
// 等しくないか
//
// -Inf==-Inf<-x<-0==+0<+x<+Inf==+Inf
//
// NaNの扱い
// どちらかがNaNのときはtrueを返す
//
public boolean ne (EFP y) {
int xf = this.flg;
int yf = y.flg;
return ((xf | yf) << 1 != 0 ? //どちらかが±0,±Inf,NaN
EFP_NE_TABLE[xf >>> 28] << (yf >>> 28 - 1) < 0
: //両方±0,±Inf,NaN以外
xf != yf || this.epp != y.epp || this.dvl != y.dvl || this.cvl != y.cvl);
} //efp.ne(EFP)
//------------------------------------------------------------------------
//x = x.neg ()
// x=-x
//y = y.neg (x)
// y=-x
// 符号反転
//x = x.neg (b)
// x=b?-x:x
//y = y.neg (x, b)
// y=b?-x:x
// 条件付き符号反転
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{-$_[0]});print$g"
// echo read("../misc/efp.gp");eval("neg(x)=-x");graph(neg) | gp -q
// **--------+---------+---------+---------+---------+---------+---------+---------+
// |*** | |
// | *** | |
// | *** | |
// | *** | |
// + *** + +
// | *** | |
// | *** | |
// | *** | |
// | *** | |
// + *** + +
// | *** | |
// | *** | |
// | *** | |
// | *** | |
// + *** + +
// | *** | |
// | *** | |
// | *** | |
// | ***| |
// +---------+---------+---------+--------***--------+---------+---------+---------+
// | |*** |
// | | *** |
// | | *** |
// | | *** |
// + + *** +
// | | *** |
// | | *** |
// | | *** |
// | | *** |
// + + *** +
// | | *** |
// | | *** |
// | | *** |
// | | *** |
// + + *** +
// | | *** |
// | | *** |
// | | *** |
// | | ***|
// +---------+---------+---------+---------+---------+---------+---------+--------**
//
public final EFP neg () {
return this.finish (0 <= this.flg << 3 ? this.flg ^ M : this.flg, this.epp, this.dvl, this.cvl, 0L); //NaN以外のとき符号反転
} //efp.neg()
public final EFP ineg () {
if (0 <= this.flg << 3) { //NaN以外のとき
this.flg ^= M; //符号反転
}
return this;
} //efp.ineg()
public final EFP neg (boolean b) {
return this.finish (b && 0 <= this.flg << 3 ? this.flg ^ M : this.flg, this.epp, this.dvl, this.cvl, 0L); //bかつNaN以外のとき符号反転
} //efp.neg(boolean)
public final EFP ineg (boolean b) {
if (b && 0 <= this.flg << 3) { //bかつNaN以外のとき
this.flg ^= M; //符号反転
}
return this;
} //efp.ineg(boolean)
public final EFP neg (EFP x) {
return this.finish (0 <= x.flg << 3 ? x.flg ^ M : x.flg, x.epp, x.dvl, x.cvl, 0L); //NaN以外のとき符号反転
} //efp.neg(EFP)
public final EFP ineg (EFP x) {
this.flg = 0 <= x.flg << 3 ? x.flg ^ M : x.flg; //NaN以外のとき符号反転
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
return this;
} //efp.ineg(EFP)
public final EFP neg (EFP x, boolean b) {
return this.finish (b && 0 <= x.flg << 3 ? x.flg ^ M : x.flg, x.epp, x.dvl, x.cvl, 0L); //bかつNaN以外のとき符号反転
} //efp.neg(EFP,boolean)
public final EFP ineg (EFP x, boolean b) {
this.flg = b && 0 <= x.flg << 3 ? x.flg ^ M : x.flg; //bかつNaN以外のとき符号反転
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
return this;
} //efp.ineg(EFP,boolean)
//------------------------------------------------------------------------
//x = x.negdec ()
// x=1-x
//y = y.negdec (x)
// y=1-x
// 1から引く(逆デクリメント)
//
// x.dec(y).neg()と同じ
//
public final EFP negdec () {
return this.inner ().dec ().outer ().neg (0 <= this.flg << 1); //x-1==+0のとき1-x==+0にするため符号反転しない
} //efp.negdec()
public final EFP negdec (EFP x) {
return this.inner ().dec (x).outer ().neg (0 <= this.flg << 1); //x-1==+0のとき1-x==+0にするため符号反転しない
} //efp.negdec(EFP)
//------------------------------------------------------------------------
//y = y.negset0 ()
// -0代入
//
public final EFP negset0 () {
this.flg = M | Z;
//this.epp = 0;
//this.dvl = 0L;
//this.cvl = 0L;
return this;
} //efp.negset0()
//------------------------------------------------------------------------
//y = y.negset1 ()
// -1代入
//
public final EFP negset1 () {
this.flg = M;
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
return this;
} //efp.negset1()
//------------------------------------------------------------------------
//y = y.negsetinf ()
// -Inf代入
//
public final EFP negsetinf () {
this.flg = M | I;
//this.epp = 0;
//this.dvl = 0L;
//this.cvl = 0L;
return this;
} //efp.negsetinf()
//------------------------------------------------------------------------
//x = x.negsub (y)
// x=y-x
// 逆減算
//
// x.sub(y).neg()と同じ
// z.negsub(x,y)はz.sub(y,x)と同じ
//
public final EFP negsub (EFP y) {
int xf = y.flg;
int xe = y.epp;
long xd = y.dvl;
long xc = y.cvl;
long xb = 0L;
int yf = this.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf | yf) << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
return this;
}
if ((xf & yf) << 2 < 0 && xf == yf) { //両方±Infで符号が同じときNaN
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N;
return this;
}
if ((xf & yf) << 1 < 0 && xf == yf) { //両方±0で符号が同じとき
this.flg = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
return this;
}
if (xf << 1 < 0 || yf << 2 < 0) { //xが±0またはyが±Infのとき-y
xf = yf ^ M;
xe = this.epp;
xd = this.dvl;
xc = this.cvl;
}
//xが±Infまたはyが±0のときx
} else { //両方±0,±Inf,NaN以外
//減算なのでyの符号を反転して加算する
yf ^= M;
long yd = this.dvl;
long yc = this.cvl;
int o = xe - this.epp;
if (o < 0 || o == 0 && (xd < yd || xd == yd && xc >>> 1 < yc >>> 1)) { //yの方が絶対値が大きい
//xとyを入れ換える
xf = yf;
xe += o = -o; //xe=this.epp
xd = yd;
xc = yc;
yf = y.flg; //後で符号を比較するときに使う
yd = y.dvl;
yc = y.cvl;
}
//xの方が絶対値が大きいか等しい
//yを右にずらして小数点の位置を合わせる
if (0 < o) {
if (o <= 63) {
xb = yc << -o;
yc = yd << -o | yc >>> o;
yd >>>= o;
} else if (o == 64) {
xb = yc;
yc = yd;
yd = 0L;
} else if (o <= 127) {
xb = yd << -o | yc;
yc = yd >>> o;
yd = 0L;
} else {
xb = yd | yc; //絶対値減算を行うとき下位からのボローとして必要
yc = 0L;
yd = 0L;
}
}
//絶対値加算または絶対値減算を行う
if (xf == yf) { //符号が同じなので絶対値加算を行う
//yc[1]とyc[0]をsticky bitに押し出す
xb |= yc << 62;
//右にずらしてxd[63]を空ける
xc = xd << 63 | xc >>> 1;
xd >>>= 1;
yc = yd << 63 | yc >>> 1;
yd >>>= 1;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//足す
xc += yc;
xd += yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//溢れの処理
if (xd < 0L) { //溢れたとき
xe++;
} else { //溢れなかったとき
xd = xd << 1 | xc >>> 63; //左にずらしてxd[63]を詰める
xc <<= 1;
}
} else { //符号が異なるので絶対値減算を行う
//yc[0]をsticky bitに押し出す
xb |= yc << 63;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//引く
// xの方が絶対値が大きいか等しいので負になることはないが0になることがある
if (xb != 0L) {
xc--;
}
xc -= yc;
xd -= yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//正規化する
if (0L <= xd) {
if (xd != 0L) {
xe -= o = Long.numberOfLeadingZeros (xd);
xd = xd << o | xc >>> -o;
xc <<= o;
} else if (xc != 0L) {
xe -= o = 64 + Long.numberOfLeadingZeros (xc);
xd = xc << o;
xc = 0L;
} else { //0になった
xf = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
}
}
} //if 符号が同じなので絶対値加算を行う/符号が異なるので絶対値減算を行う
} //if どちらかが±0,±Inf,NaN/両方±0,±Inf,NaN以外
return this.finish (xf, xe, xd, xc, xb);
} //efp.negsub(EFP)
public final EFP negsub (EFP x, EFP y) {
int xf = y.flg;
int xe = y.epp;
long xd = y.dvl;
long xc = y.cvl;
long xb = 0L;
int yf = x.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf | yf) << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
return this;
}
if ((xf & yf) << 2 < 0 && xf == yf) { //両方±Infで符号が同じときNaN
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N;
return this;
}
if ((xf & yf) << 1 < 0 && xf == yf) { //両方±0で符号が同じとき
this.flg = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
return this;
}
if (xf << 1 < 0 || yf << 2 < 0) { //xが±0またはyが±Infのとき-y
xf = yf ^ M;
xe = x.epp;
xd = x.dvl;
xc = x.cvl;
}
//xが±Infまたはyが±0のときx
} else { //両方±0,±Inf,NaN以外
//減算なのでyの符号を反転して加算する
yf ^= M;
long yd = x.dvl;
long yc = x.cvl;
int o = xe - x.epp;
if (o < 0 || o == 0 && (xd < yd || xd == yd && xc >>> 1 < yc >>> 1)) { //yの方が絶対値が大きい
//xとyを入れ換える
xf = yf;
xe += o = -o; //xe=x.epp
xd = yd;
xc = yc;
yf = y.flg; //後で符号を比較するときに使う
yd = y.dvl;
yc = y.cvl;
}
//xの方が絶対値が大きいか等しい
//yを右にずらして小数点の位置を合わせる
if (0 < o) {
if (o <= 63) {
xb = yc << -o;
yc = yd << -o | yc >>> o;
yd >>>= o;
} else if (o == 64) {
xb = yc;
yc = yd;
yd = 0L;
} else if (o <= 127) {
xb = yd << -o | yc;
yc = yd >>> o;
yd = 0L;
} else {
xb = yd | yc; //絶対値減算を行うとき下位からのボローとして必要
yc = 0L;
yd = 0L;
}
}
//絶対値加算または絶対値減算を行う
if (xf == yf) { //符号が同じなので絶対値加算を行う
//yc[1]とyc[0]をsticky bitに押し出す
xb |= yc << 62;
//右にずらしてxd[63]を空ける
xc = xd << 63 | xc >>> 1;
xd >>>= 1;
yc = yd << 63 | yc >>> 1;
yd >>>= 1;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//足す
xc += yc;
xd += yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//溢れの処理
if (xd < 0L) { //溢れたとき
xe++;
} else { //溢れなかったとき
xd = xd << 1 | xc >>> 63; //左にずらしてxd[63]を詰める
xc <<= 1;
}
} else { //符号が異なるので絶対値減算を行う
//yc[0]をsticky bitに押し出す
xb |= yc << 63;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//引く
// xの方が絶対値が大きいか等しいので負になることはないが0になることがある
if (xb != 0L) {
xc--;
}
xc -= yc;
xd -= yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//正規化する
if (0L <= xd) {
if (xd != 0L) {
xe -= o = Long.numberOfLeadingZeros (xd);
xd = xd << o | xc >>> -o;
xc <<= o;
} else if (xc != 0L) {
xe -= o = 64 + Long.numberOfLeadingZeros (xc);
xd = xc << o;
xc = 0L;
} else { //0になった
xf = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
}
}
} //if 符号が同じなので絶対値加算を行う/符号が異なるので絶対値減算を行う
} //if どちらかが±0,±Inf,NaN/両方±0,±Inf,NaN以外
return this.finish (xf, xe, xd, xc, xb);
} //efp.negsub(EFP,EFP)
//------------------------------------------------------------------------
//x = x.nextdowne ()
//y = y.nextdowne (x)
// EFPで表現できるxの-Inf側の隣接値
//x = x.nextdownd ()
//y = y.nextdownd (x)
// doubleで表現できるxよりも小さい最大の値
//x = x.nextdownf ()
//y = y.nextdownf (x)
// floatで表現できるxよりも小さい最大の値
//x = x.nextdownx ()
//y = y.nextdownx (x)
// extendedで表現できるxよりも小さい最大の値
//x = x.nextdowny ()
//y = y.nextdowny (x)
// tripleで表現できるxよりも小さい最大の値
//x = x.nextdown (prec)
//y = y.nextdown (x, prec)
// precの精度で表現できるxよりも小さい最大の値
//
// nextdown(±0)=負の最小値
// nextdown(+Inf)=最大値
// nextdown(-Inf)=-Inf
// nextdown(NaN)=NaN
// nextdown(最小値)=-Inf
//
public final EFP nextdowne () {
return this.nextdowne (this);
} //efp.nextdowne()
public final EFP nextdowne (EFP x) {
int xf = x.flg;
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
xf = M; //負の最大値
xe = -32768;
xd = MSB;
xc = 0L;
} else if (xf == (P | I)) { //+Inf
xf = P; //最大値
xe = 32767;
xd = -1L;
xc = -1L << 128 - LEN;
}
//-Inf,NaNはそのまま
} else if (xf >= 0) { //+x
if (xc != 0L) {
xc -= 1L << 128 - LEN; //最下位bitから1を引く
} else if (xd != MSB) {
xc = -1L << 128 - LEN;
xd--;
} else if (xe > -32768) {
xc = -1L << 128 - LEN;
xd = -1L;
xe--;
} else { //アンダーフロー
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.set0 (); //+0
}
} else { //-x
if (xc != -1L << 128 - LEN) {
xc += (1L << 128 - LEN); //最下位bitに1を加える
} else if (xd != -1L) {
xc = 0L;
xd++;
} else if (xe < 32767) {
xc = 0L;
xd = MSB;
xe++;
} else { //オーバーフロー
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = xd;
return this.negsetinf (); //-Inf
}
}
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = xc;
return this;
} //efp.nextdowne(EFP)
public final EFP nextdownd () {
return this.nextdowne (this).roundd (EPB_MODE_RM);
} //efp.nextdownd()
public final EFP nextdownd (EFP x) {
return this.nextdowne (x).roundd (EPB_MODE_RM);
} //efp.nextdownd(EFP)
public final EFP nextdownf () {
return this.nextdowne (this).roundf (EPB_MODE_RM);
} //efp.nextdownf()
public final EFP nextdownf (EFP x) {
return this.nextdowne (x).roundf (EPB_MODE_RM);
} //efp.nextdownf(EFP)
public final EFP nextdowng () {
return this.nextdowne (this).roundg (EPB_MODE_RM);
} //efp.nextdowng()
public final EFP nextdowng (EFP x) {
return this.nextdowne (x).roundg (EPB_MODE_RM);
} //efp.nextdowng(EFP)
public final EFP nextdownx () {
return this.nextdowne (this).roundx (EPB_MODE_RM);
} //efp.nextdownx()
public final EFP nextdownx (EFP x) {
return this.nextdowne (x).roundx (EPB_MODE_RM);
} //efp.nextdownx(EFP)
public final EFP nextdowny () {
return this.nextdowne (this).roundy (EPB_MODE_RM);
} //efp.nextdowny()
public final EFP nextdowny (EFP x) {
return this.nextdowne (x).roundy (EPB_MODE_RM);
} //efp.nextdowny(EFP)
public final EFP nextdown (int prec) {
switch (prec) {
case EPB_PREC_EXD:
return this.nextdowne (this).roundx (EPB_MODE_RM);
case EPB_PREC_SGL:
return this.nextdowne (this).roundf (EPB_MODE_RM);
case EPB_PREC_DBL:
case EPB_PREC_DBL3:
return this.nextdowne (this).roundd (EPB_MODE_RM);
case EPB_PREC_TPL:
return this.nextdowne (this).roundy (EPB_MODE_RM);
case EPB_PREC_XSG:
return this.nextdowne (this).roundg (EPB_MODE_RM);
}
return this.nextdowne (this);
} //efp.nextdown(int)
public final EFP nextdown (EFP x, int prec) {
switch (prec) {
case EPB_PREC_EXD:
return this.nextdowne (x).roundx (EPB_MODE_RM);
case EPB_PREC_SGL:
return this.nextdowne (x).roundf (EPB_MODE_RM);
case EPB_PREC_DBL:
case EPB_PREC_DBL3:
return this.nextdowne (x).roundd (EPB_MODE_RM);
case EPB_PREC_TPL:
return this.nextdowne (x).roundy (EPB_MODE_RM);
case EPB_PREC_XSG:
return this.nextdowne (x).roundg (EPB_MODE_RM);
}
return this.nextdowne (x);
} //efp.nextdown(EFP,int)
//------------------------------------------------------------------------
//x = x.nextupe ()
//y = y.nextupe (x)
// EFPで表現できる+Inf側の隣接値
//x = x.nextupd ()
//y = y.nextupd (x)
// doubleで表現できるxよりも大きい最小の値
//x = x.nextupf ()
//y = y.nextupf (x)
// floatで表現できるxよりも大きい最小の値
//x = x.nextupx ()
//y = y.nextupx (x)
// extendedで表現できるxよりも大きい最小の値
//x = x.nextupy ()
//y = y.nextupy (x)
// tripleで表現できるxよりも大きい最小の値
//x = x.nextup (prec)
//y = y.nextup (x, prec)
// precの精度で表現できるxよりも大きい最小の値
//
// nextup(±0)=正の最小値
// nextup(-Inf)=最小値
// nextup(+Inf)=+Inf
// nextup(NaN)=NaN
// nextup(最大値)=+Inf
//
public final EFP nextupe () {
return this.nextupe (this);
} //efp.nextupe()
public final EFP nextupe (EFP x) {
int xf = x.flg;
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
xf = P; //正の最小値
xe = -32768;
xd = MSB;
xc = 0L;
} else if (xf == (M | I)) { //-Inf
xf = M; //最小値
xe = 32767;
xd = -1L;
xc = -1L << 128 - LEN;
}
//+Inf,NaNはそのまま
} else if (xf >= 0) { //+x
if (xc != -1L << 128 - LEN) {
xc += (1L << 128 - LEN); //最下位bitに1を加える
} else if (xd != -1L) {
xc = 0L;
xd++;
} else if (xe < 32767) {
xc = 0L;
xd = MSB;
xe++;
} else { //オーバーフロー
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = xd;
return this.setinf (); //+Inf
}
} else { //-x
if (xc != 0L) {
xc -= 1L << 128 - LEN; //最下位bitから1を引く
} else if (xd != MSB) {
xc = -1L << 128 - LEN;
xd--;
} else if (xe > -32768) {
xc = -1L << 128 - LEN;
xd = -1L;
xe--;
} else { //アンダーフロー
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = xd;
return this.negset0 (); //-0
}
}
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = xc;
return this;
} //efp.nextupe(EFP)
public final EFP nextupd () {
return this.nextupe (this).roundd (EPB_MODE_RP);
} //efp.nextupd()
public final EFP nextupd (EFP x) {
return this.nextupe (x).roundd (EPB_MODE_RP);
} //efp.nextupd(EFP)
public final EFP nextupf () {
return this.nextupe (this).roundf (EPB_MODE_RP);
} //efp.nextupf()
public final EFP nextupf (EFP x) {
return this.nextupe (x).roundf (EPB_MODE_RP);
} //efp.nextupf(EFP)
public final EFP nextupg () {
return this.nextupe (this).roundg (EPB_MODE_RP);
} //efp.nextupg()
public final EFP nextupg (EFP x) {
return this.nextupe (x).roundg (EPB_MODE_RP);
} //efp.nextupg(EFP)
public final EFP nextupx () {
return this.nextupe (this).roundx (EPB_MODE_RP);
} //efp.nextupx()
public final EFP nextupx (EFP x) {
return this.nextupe (x).roundx (EPB_MODE_RP);
} //efp.nextupx(EFP)
public final EFP nextupy () {
return this.nextupe (this).roundy (EPB_MODE_RP);
} //efp.nextupy()
public final EFP nextupy (EFP x) {
return this.nextupe (x).roundy (EPB_MODE_RP);
} //efp.nextupy(EFP)
public final EFP nextup (int prec) {
switch (prec) {
case EPB_PREC_EXD:
return this.nextupe (this).roundx (EPB_MODE_RP);
case EPB_PREC_SGL:
return this.nextupe (this).roundf (EPB_MODE_RP);
case EPB_PREC_DBL:
case EPB_PREC_DBL3:
return this.nextupe (this).roundd (EPB_MODE_RP);
case EPB_PREC_TPL:
return this.nextupe (this).roundy (EPB_MODE_RP);
case EPB_PREC_XSG:
return this.nextupe (this).roundg (EPB_MODE_RP);
}
return this.nextupe (this);
} //efp.nextup(int)
public final EFP nextup (EFP x, int prec) {
switch (prec) {
case EPB_PREC_EXD:
return this.nextupe (x).roundx (EPB_MODE_RP);
case EPB_PREC_SGL:
return this.nextupe (x).roundf (EPB_MODE_RP);
case EPB_PREC_DBL:
case EPB_PREC_DBL3:
return this.nextupe (x).roundd (EPB_MODE_RP);
case EPB_PREC_TPL:
return this.nextupe (x).roundy (EPB_MODE_RP);
case EPB_PREC_XSG:
return this.nextupe (x).roundg (EPB_MODE_RP);
}
return this.nextupe (x);
} //efp.nextup(EFP,int)
//------------------------------------------------------------------------
//y = y.parse (s)
// 文字列解析
//
// 仮数部がInfで始まっているときはInf、Inf以外で仮数部に数字がないときはNaNとみなす
// 仮数部が0bで始まっているときは2進数、0oで始まっているときは8進数、0xで始まっているときは16進数、それ以外は10進数とみなす
// 0で始まっているだけでは8進数とみなさない
// 2進数と8進数と16進数は2の累乗の指数部をp~で、10進数は10の累乗の指数部をe~で指定できる
// Inf、16進数のa~f、指数部のp~とe~は大文字と小文字を区別しない
// 後ろのゴミは無視する
// 先頭に空白があるときはエラーとなってNaNが返ることに注意
//
public final EFP parse (String s) {
int i = 0;
int l = s.length ();
char c = i < l ? s.charAt (i++) : '\0';
//符号
int f;
if (c == '-') {
f = M;
c = i < l ? s.charAt (i++) : '\0';
} else {
f = P;
if (c == '+') {
c = i < l ? s.charAt (i++) : '\0';
}
}
//Inf
if (i + 1 < l && (c | 0x20) == 'i' && (s.charAt (i) | 0x20) == 'n' && (s.charAt (i + 1) | 0x20) == 'f') {
this.flg = f | I;
return this;
}
//仮数部
this.inner ();
this.flg = P | Z; //符号は最後に付ける
boolean nan = true; //true=仮数部に数字がない
//基数
int r = 10;
if (c == '$') { //16進数
c = i < l ? s.charAt (i++) : '\0';
r = 16;
} else if (c == '@') { //8進数
c = i < l ? s.charAt (i++) : '\0';
r = 8;
} else if (c == '%') { //2進数
c = i < l ? s.charAt (i++) : '\0';
r = 2;
} else if (c == '0') {
nan = false; //0xの後に数字がなくても0があるのでNaNではなくて0にする
c = i < l ? s.charAt (i++) : '\0';
if ((c | 0x20) == 'x') { //16進数
c = i < l ? s.charAt (i++) : '\0';
r = 16;
} else if ((c | 0x20) == 'o') { //8進数
c = i < l ? s.charAt (i++) : '\0';
r = 8;
} else if ((c | 0x20) == 'b') { //2進数
c = i < l ? s.charAt (i++) : '\0';
r = 2;
}
}
//整数部
{
int t = Character.digit (c, r);
if (t >= 0) {
nan = false;
do {
this.imul (EFP_DIGIT[r]).iadd (EFP_DIGIT[t]);
c = i < l ? s.charAt (i++) : '\0';
t = Character.digit (c, r);
} while (t >= 0);
}
}
//小数部
int o = 0; //-小数点以下の桁数またはbit数
if (c == '.') {
c = i < l ? s.charAt (i++) : '\0';
int t = Character.digit (c, r);
if (t >= 0) {
nan = false;
do {
o--;
this.imul (EFP_DIGIT[r]).iadd (EFP_DIGIT[t]);
c = i < l ? s.charAt (i++) : '\0';
t = Character.digit (c, r);
} while (t >= 0);
if (r == 8) { //8進数のときは1桁が3bit
o *= 3;
} else if (r == 16) { //16進数のときは1桁が4bit
o <<= 2;
}
}
}
//NaN
if (nan) { //仮数部に数字がない
this.flg = N;
return this.outer ();
}
//0
if (this.flg << 1 < 0) { //Z
this.flg = f | Z;
return this.outer ();
}
//指数部
if ((c | 0x20) == (r == 10 ? 'e' : 'p')) {
c = i < l ? s.charAt (i++) : '\0';
int m; //指数部の符号
if (c == '-') {
m = -1;
c = i < l ? s.charAt (i++) : '\0';
} else {
m = 1;
if (c == '+') {
c = i < l ? s.charAt (i++) : '\0';
}
}
if ('0' <= c && c <= '9') { //指数部は常に10進数
int t = 0;
do {
t = t * 10 + (c - '0');
if (t >= 100000000) { //オーバーフローまたはアンダーフロー
this.outer ();
if (m >= 0) { //オーバーフロー
//0e+999999999は0だが0は除外済み
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = 0;
epbExceptionOperandMantissa = 0L;
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | f >>> 31]).finish (); //±Inf
} else { //アンダーフロー
//1e-999999999は0
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = 0;
epbExceptionOperandMantissa = 0L;
return this.sete (UNFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | f >>> 31]).finish (); //±0
}
}
c = i < l ? s.charAt (i++) : '\0';
} while ('0' <= c && c <= '9');
o += m * t; //指数部-小数点以下の桁数
}
}
if (r != 10) { //2^oを掛ける
this.shl (o); //8進数または16進数のときも指数部はbit単位
} else if (o > 0) { //10^oを掛ける
//this.imul (new EFP (TEN).pow (o));
EFP t = new EFP (ONE);
for (int j = 0, m = o; m != 0; j++, m >>>= 1) {
if ((m & 1) != 0) {
t.imul (EFP_TEN_POWER_P[j]);
}
}
this.imul (t);
} else if (o < 0) { //10^-oで割る
//this.div (new EFP (TEN).pow (-o));
EFP t = new EFP (ONE);
for (int j = 0, m = -o; m != 0; j++, m >>>= 1) {
if ((m & 1) != 0) {
t.imul (EFP_TEN_POWER_P[j]);
}
}
this.div (t);
}
//符号
return this.outer ().neg (f < 0);
} //efp.parse(String)
//------------------------------------------------------------------------
//x = x.pow (y)
// x=x^y
//z = z.pow (x, y)
// z=x^y
// 累乗
//
// 指数関数との関係
// x^y=(e^(log(x)))^y
// =e^(log(x)*y)
// =(2^(log2(x)))^y
// =2^(log2(x)*y)
//
// メモ
// log2(x)はxが0に近すぎると-Infになってしまう
// x=2^k*v
// log2(2^k*v)=k+log2(v)
// x^y=2^(log2(x)*y)
// =2^(log2(2^k*v)*y)
// =2^((k+log2(v))*y)
// =2^(k*y+log2(v)*y)
// =2^(k*y)*2^(log2(v)*y)
//
public final EFP pow (EFP y) {
return this.pow (this, y);
} //efp.pow(EFP)
public final EFP pow (EFP x, EFP y) {
int xf = x.flg;
int yf = y.flg;
if (yf << 1 != 0) { //yが±0,±Inf,NaN
if (yf << 1 < 0) {
this.flg = P; //x^±0=1。NaN^±0=1を含む
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
return this;
} else {
int s;
this.flg = (yf << 3 < 0 || //x^NaN=NaN
xf << 3 < 0 || //NaN^(y!=±0)=NaN
(s = x.cmp1abs ()) == 0 ? N : //(|x|==1)^±Inf=NaN
(s ^ yf) >= 0 ? P | I : //(|x|>1)^+Inf=(|x|<1)^-Inf=+Inf。±Inf^±Inf=+Infを含む
P | Z); //(|x|>1)^-Inf=(|x|<1)^+Inf=+0。±Inf^∓Inf=+0を含む
return this;
}
} else if (xf << 1 != 0) { //xが±0,±Inf,NaNでyが±0,±Inf,NaN以外
this.flg = (xf << 3 < 0 ? N : //NaN^(y!=±0)=NaN
xf >= 0 ? //xが+0,+Inf
(xf << 2 ^ yf) >= 0 ? P | Z : //+0^(y>0)=+0,+Inf^(y<0)=+0
P | I : //+0^(y<0)=+Inf,+Inf^(y>0)=+Inf
//xが-0,-Inf
y.isodd () ? //yが奇数
(xf << 2 ^ yf) >= 0 ? M | Z : //-0^(y>0 and is odd)=-0,-Inf^(y<0 and is odd)=-0
M | I : //-0^(y<0 and is odd)=-Inf,-0^(y<0 and is odd)=-Inf
//yが奇数でない(偶数であるまたは整数でない)
//!!! (-Inf)^-1.5は+0なのか?
// System.out.println(Math.pow(Double.NEGATIVE_INFINITY,-1.5));
// 0.0
(xf << 2 ^ yf) >= 0 ? P | Z : //-0^(y>0 and is not odd)=+0,-Inf^(y<0 and is even)=+0
P | I); //-0^(y<0 and is even)=+Inf,-Inf^(y>0 and is even)=+Inf
return this;
} else if (xf < 0) { //両方±0,±Inf,NaN以外でxが負
this.inner ();
if (y.iseven ()) { //yが偶数
EFP w = new EFP ();
this.imulw (w, new EFP ().ineg (x).log2 (), y);
if (this.epp >= 16) { //指数が大きすぎる
this.flg = this.flg >= 0 ? P | I : P | Z; //2^+big=+Inf,2^-big=+0
return this.outer ();
} else {
int k = this.geti ();
return this.frac ().iadd (w).exp2 ().outer ().shl (k);
}
} else if (y.isodd ()) { //yが奇数
EFP w = new EFP ();
this.imulw (w, new EFP ().ineg (x).log2 (), y);
if (this.epp >= 16) { //指数が大きすぎる
this.flg = this.flg >= 0 ? M | I : M | Z; //-(2^+big)=-Inf,-(2^-big)=-0
return this.outer ();
} else {
int k = this.geti ();
return this.frac ().iadd (w).exp2 ().shl (k).outer ().neg ();
}
} else { //yが整数でない
this.flg = N; //(x<0)^(y is not integer)=NaN
return this.outer ();
}
} else { //両方±0,±Inf,NaN以外でxが正
this.inner ();
EFP w = new EFP ();
this.imulw (w, new EFP ().log2 (x), y);
if (this.epp >= 16) { //指数が大きすぎる
this.flg = this.flg >= 0 ? P | I : P | Z; //2^+big=+Inf,2^-big=+0
return this.outer ();
} else {
int k = this.geti ();
return this.frac ().iadd (w).exp2 ().outer ().shl (k);
}
}
} //efp.pow(EFP,EFP)
//------------------------------------------------------------------------
//x = x.powi (n)
// x=x^n
//z = z.powi (x, n)
// z=x^n
// int累乗
//
public final EFP powi (int n) {
return this.powi (this, n);
} //efp.powi(int)
public final EFP powi (EFP x, int n) {
int xf = x.flg;
if (n == 0) { //yが±0,±Inf,NaN
//this.set1 ();
this.flg = P; //x^±0=1。NaN^±0=1を含む
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
return this;
} else if (xf << 1 != 0) { //xが±0,±Inf,NaNでyが±0,±Inf,NaN以外
this.flg = (xf << 3 < 0 ? N : //NaN^(y!=±0)=NaN
xf >= 0 ? //xが+0,+Inf
(xf << 2 ^ n) >= 0 ? P | Z : //+0^(y>0)=+0,+Inf^(y<0)=+0
P | I : //+0^(y<0)=+Inf,+Inf^(y>0)=+Inf
//xが-0,-Inf
(n & 1) != 0 ? //yが奇数
(xf << 2 ^ n) >= 0 ? M | Z : //-0^(y>0 and is odd)=-0,-Inf^(y<0 and is odd)=-0
M | I : //-0^(y<0 and is odd)=-Inf,-0^(y<0 and is odd)=-Inf
//yが奇数でない(偶数であるまたは整数でない)
//!!! (-Inf)^-1.5は+0なのか?
// System.out.println(Math.pow(Double.NEGATIVE_INFINITY,-1.5));
// 0.0
(xf << 2 ^ n) >= 0 ? P | Z : //-0^(y>0 and is not odd)=+0,-Inf^(y<0 and is even)=+0
P | I); //-0^(y<0 and is even)=+Inf,-Inf^(y>0 and is even)=+Inf
return this;
} else { //両方±0,±Inf,NaN以外
// y==0は処理済み
int t = n >= 0 ? n : -n; //|y|
if (t >>> 16 != 0) { //t==0x80000000の場合があるのでt>65535は不可
//|x|が1に近くて|n|が大きいとき乗算を繰り返す方法では誤差が大きくなるのでpowに計算させる
int xe = x.epp;
long xd = x.dvl;
if (xe == 0 && xd >>> -16 == 0x8000L ||
xe == -1 && xd >>> -16 == 0xffffL) { //±1±ε
return this.pow (x, new EFP (n));
}
}
this.inner ();
EFP w = new EFP (x); //x^(2^0)
if ((t & 1) == 0) {
//this.set1 ();
this.flg = P; //x^0=1
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
} else {
//this.sete (x);
this.flg = xf; //x^1=x
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
}
while ((t >>>= 1) != 0) {
w.squ (); //x^(2^k)。指数部分が32bitでも足りなくなることがあるのでisquは不可
if ((t & 1) != 0) {
this.mul (w);
}
}
if (n < 0) { //x^(y<0)=1/x^-y
this.rcp ();
}
return this.outer ().finish ();
}
} //efp.powi(EFP,int)
//------------------------------------------------------------------------
//x = x.quo (y)
// x=trunc(x/y)
//z = z.quo (x, y)
// z=trunc(x/y)
// 商
//
public final EFP quo (EFP y) {
return this.quo (this, y);
} //efp.quo(EFP)
public final EFP quo (EFP x, EFP y) {
int xf = x.flg;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
this.flg = ((xf | yf) << 3 != 0 || (xf & yf & (Z | I)) != 0 ? N : //どちらかがNaNまたは±0/±0または±Inf/±InfのときNaN
(xf ^ yf) & M | ((xf & Z | yf & I) != 0 ? Z : I)); //±0/(±0,NaN以外)または(±Inf,NaN以外)/±Infのとき±0、(±0,NaN以外)/±0または±Inf/(±Inf,NaN以外)のとき±Inf
return this;
}
//±0,±Inf,NaN以外
int zf = xf ^ yf; //符号が同じならばP、異なればM。ここでセットされるのはMだけ
int ze = x.epp - y.epp; //商の小数点はq0の左端から右にzeの位置
if (ze < 0) { //|x|<|y|。商は0
this.flg = zf | Z;
return this;
}
//仮数部を31bitずつ3分割する
long r01 = x.dvl;
long y01 = y.dvl;
long r2 = (r01 << -2 | x.cvl >>> 2) >>> 33;
long y2 = (y01 << -2 | y.cvl >>> 2) >>> 33;
r01 >>>= 2;
y01 >>>= 2;
long y0 = y01 >>> 31;
long y1 = y01 & 0x7fffffffL;
//先頭1bit
boolean qq;
if (r01 < y01 || (r01 == y01 && r2 < y2)) { //xの仮数部<yの仮数部
if (ze == 0) { //|x|<|y|。商は0
this.flg = zf | Z;
return this;
}
qq = false;
} else {
qq = true;
r2 -= y2;
r01 -= y01;
if (r2 < 0L) {
r2 += 0x80000000L;
r01--;
}
}
long q0, q1, q2;
//1桁目
q0 = r01 >> 31 == y0 ? 0x7fffffffL : r01 / y0;
r01 = (r01 - q0 * y0 << 31) + r2 - q0 * y1;
if (r01 < 0L) {
q0--;
r01 += y01;
}
r2 = q0 * y2 + 0x7fffffffL;
r01 -= r2 >> 31;
r2 = ~r2 & 0x7fffffffL; //~(r2 | ~0x7fffffffL)
if (r01 < 0L) {
q0--;
r2 += y2;
r01 += y01 + (r2 >> 31);
r2 &= 0x7fffffffL;
}
if (ze <= 31) {
q0 &= ~0x7fffffffL >> ze;
q1 = q2 = 0L;
} else {
//2桁目
q1 = r01 >> 31 == y0 ? 0x7fffffffL : r01 / y0;
r01 = (r01 - q1 * y0 << 31) + r2 - q1 * y1;
if (r01 < 0L) {
q1--;
r01 += y01;
}
r2 = q1 * y2 + 0x7fffffffL;
r01 -= r2 >> 31;
r2 = ~r2 & 0x7fffffffL; //~(r2 | ~0x7fffffffL)
if (r01 < 0L) {
q1--;
r2 += y2;
r01 += y01 + (r2 >> 31);
r2 &= 0x7fffffffL;
}
if (ze <= 62) {
q1 &= ~0x7fffffffL >> ze - 31;
q2 = 0L;
} else {
//3桁目
q2 = r01 >> 31 == y0 ? 0x7fffffffL : r01 / y0;
r01 = (r01 - q2 * y0 << 31) + r2 - q2 * y1;
if (r01 < 0L) {
q2--;
r01 += y01;
}
r2 = q2 * y2 + 0x7fffffffL;
r01 -= r2 >> 31;
r2 = ~r2 & 0x7fffffffL; //~(r2 | ~0x7fffffffL)
if (r01 < 0L) {
q2--;
//r2 += y2;
//r01 += y01 + (r2 >> 31);
//r2 &= 0x7fffffffL;
}
if (ze <= 93) {
q2 &= ~0x7fffffffL >> ze - 62;
}
}
}
//商 (((qq ? 1 : 0) << 31 | q0) << 31 | q1) << 31 | q2
//正規化する
if (qq) { //商は94bit
q0 = MSB | q0 << 32 | q1 << 1 | q2 >>> 30;
q2 <<= -30;
} else { //商は93bit
ze--;
q0 = q0 << -31 | q1 << 2 | q2 >>> 29;
q2 <<= -29;
}
return this.finish (zf, ze, q0, q2, 0L);
} //efp.quo(EFP,EFP)
//------------------------------------------------------------------------
//x = x.rad ()
// x*=pi/180
//y = y.rad (x)
// y=x*pi/180
// pi/180倍(ラジアン)
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{atan2(1,1)/45*$_[0]});print$g"
// echo read("../misc/efp.gp");eval("rad(x)=x*(Pi/180)");graph(rad) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// *********************************************************************************
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
public final EFP rad () {
return this.mul (this, TO_RAD); //x*pi/180
} //efp.rad()
public final EFP rad (EFP x) {
return this.mul (x, TO_RAD); //x*pi/180
} //efp.rad(EFP)
//------------------------------------------------------------------------
//y = y.random ()
// y=random()
// 乱数
//
// 0以上1未満の乱数
// 0以上1未満の1/2^LENの倍数がほぼ一様に出現するはず
// 指数部が小さい数は有効桁数が少ない
//
public final EFP random () {
int xf = P;
int xe = -1;
long xd = epbRand48 ();
long xc = epbRand48 ();
xd = xd << 16 | xc >>> 32;
xc = xc << 32 & -LSB;
if (xd != 0L) {
int o = Long.numberOfLeadingZeros (xd);
if (o > 0) {
xe -= o;
xd = xd << o | xc >>> -o;
xc <<= o;
}
} else if (xc != 0L) {
int o = Long.numberOfLeadingZeros (xc);
xe -= 64 + o;
xd = xc << o;
xc = 0L;
} else {
xf = P | Z;
}
return this.finish (xf, xe, xd, xc, 0L);
} //efp.random()
//------------------------------------------------------------------------
//x = x.rcp ()
// x=1/x
//y = y.rcp (x)
// y=1/x
// 逆数 reciprocal
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{1/$_[0]});print$g"
// echo read("../misc/efp.gp");eval("rcp(x)=1/x");graph(rcp) | gp -q
// +---------+---------+---------+---------+-**------+---------+---------+---------+
// | | * |
// | | * |
// | | * |
// | | * |
// + + * +
// | | ** |
// | | * |
// | | * |
// | | ** |
// + + * +
// | | ** |
// | | ** |
// | | ** |
// | | ** |
// + + *** +
// | | **** |
// | | ******* |
// | | ************** |
// | | ********
// +---------+---------+---------+---------+---------+---------+---------+---------+
// ******** | |
// | ************** | |
// | ******* | |
// | **** | |
// + *** + +
// | ** | |
// | ** | |
// | ** | |
// | ** | |
// + * + +
// | ** | |
// | * | |
// | * | |
// | ** | |
// + * + +
// | * | |
// | * | |
// | * | |
// | * | |
// +---------+---------+---------+------**-+---------+---------+---------+---------+
//
// ニュートン法
// f(x)=a-1/x
// f'(x)=1/x^2
// x'=x-f(x)/f'(x)
// =x-(a-1/x)/(1/x^2)
// =x-(a*x^2-x)
// =2*x-a*x^2
//
public final EFP rcp () {
return this.div (ONE, this);
} //efp.rcp()
public final EFP rcp (EFP x) {
if (false) { //1を割る。[93] 55.7ns。正確だが遅い
return this.div (ONE, x);
} else { //ニュートン法。[91] 37.0ns。速いが誤差が大きい
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
epbFpsr |= EPB_FPSR_DZ;
epbExceptionOperandExponent = xf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = xf ^ (Z | I); //1/±0=±Inf
} else if (xf << 2 < 0) { //±Inf
this.flg = xf ^ (Z | I); //1/±Inf=±0
} else { //NaN
this.flg = N;
}
return this;
}
//±0,±Inf,NaN以外
this.inner ();
long s = Double.doubleToLongBits (1.0 / Double.longBitsToDouble ((long) 1023 << 52 | x.dvl << 1 >>> 12));
EFP t = new EFP (xf, (int) (s >>> 52) - 1023 - x.epp, MSB | s << 12 >>> 1, 0L);
//return this.imul (x, t).negsub (TWO).outer ().mul (t); //(2-x*t)*t。[91] 38.4ns
this.imul2 (t); //2*t
t.isqu ().imul (x); //x*t^2
return this.outer ().sub (t); //2*t-x*t^2。[91] 37.0ns。mulがsquになっている分速い
}
} //efp.rcp(EFP)
//------------------------------------------------------------------------
//x = x.rcpdiv (y)
// x=y/x
// 逆除算
//
// x.div(y).rcp()と同じ
// z.rcpdiv(x,y)はz.div(y,x)と同じ
//
public final EFP rcpdiv (EFP y) {
return this.div (y, this);
} //efp.rcpdiv(EFP)
public final EFP rcpdiv (EFP x, EFP y) {
return this.div (y, x);
} //efp.rcpdiv(EFP,EFP)
//------------------------------------------------------------------------
//x = x.rem (y)
// x%=y
//z = z.rem (x, y)
// z=x%y
// 剰余(round-to-zero)
//
// x%y=x-trunc(x/y)*y
// (xn/xd)-trunc(x/y)*(yn/yd)
// =(xn/xd)-((trunc(x/y)*yn)/yd)
// =(xn*yd-xd*((trunc(x/y)*yn))/(xd*yd)
//
// Javaのx%yと同じ
// x%y=x-(x/y)*y
// =isNaN(x)||isNaN(y)||isInfinite(x)?NaN:isInfinite(y)?x:(t=x-trunc(x/y)*y)==0?copySign(0,x):t
// Javaの%演算子はdoubleをdoubleのまま計算する
// 被除数から0の方向にある最も近い除数の倍数を引いた結果を返す
// 倍数の符号は任意なので除数の符号は結果に影響しない
// 5.0 % 3.0 == 5.0 - (long) ( 5.0 / 3.0) * 3.0 == 2.0
// 5.0 % -3.0 == 5.0 - (long) ( 5.0 / -3.0) * -3.0 == 2.0
// -5.0 % 3.0 == -5.0 - (long) (-5.0 / 3.0) * 3.0 == -2.0
// -5.0 % -3.0 == -5.0 - (long) (-5.0 / -3.0) * -3.0 == -2.0
// z 余り remainder
// x 被除数 dividend
// y 除数 divisor
//
public final EFP rem (EFP y) {
return this.rem (this, y);
} //efp.rem(EFP)
public final EFP rem (EFP x, EFP y) {
int xf = x.flg;
int yf = y.flg;
epbFpsr &= 0xff00ffff; //quotient byteをクリアする
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf | yf) << 3 < 0) { //rem(NaN,y)=NaN, rem(x,NaN)=NaN
this.flg = N;
} else if (xf << 2 < 0 || //rem(±Inf,y)=NaN
yf << 1 < 0) { //rem(x,±0)=NaN
//除数が±0でもゼロ除算にはならない
epbFpsr |= EPB_FPSR_OE;
if (yf << 1 < 0) { //±0
epbExceptionOperandExponent = yf & M;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else if (yf << 2 < 0) { //±Inf
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //±y
epbExceptionOperandExponent = yf & M | 0x3fff + y.epp << 16;
epbExceptionOperandMantissa = y.dvl;
}
this.flg = N;
} else if (xf << 1 < 0) { //rem(±0,y)=±0
epbFpsr |= ((xf ^ yf) & M) >>> 8; //quotient byteに商の符号を入れる
this.flg = xf;
} else { //rem(x,±Inf)=x
epbFpsr |= ((xf ^ yf) & M) >>> 8; //quotient byteに商の符号を入れる
this.finish (xf, x.epp, x.dvl, x.cvl, 0L); //xが非正規化数のときUFをセットする
}
return this;
}
//両方±0,±Inf,NaN以外
epbFpsr |= ((xf ^ yf) & M) >>> 8; //quotient byteに商の符号を入れる
if (false) {
this.inner ();
//this.sub (x, new EFP ().div (x, y).trunc ().imul (y)); //x-trunc(x/y)*y。this==x||this==yの場合に注意
int s;
long t;
if ((s = x.epp - y.epp) < 0 ||
s == 0 && ((t = x.dvl - y.dvl) < 0L ||
t == 0L && (x.cvl >>> 1) - (y.cvl >>> 1) < 0L)) { //|x|<|y|。商が0
//this.sete (x); //被除数がそのまま余りになる
this.flg = xf;
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
} else { //|x|>=|y|。商が0ではない
EFP xx = x != this ? x : new EFP (x); //xのコピー
EFP yy = y != this ? y : new EFP (y); //yのコピー
this.divrz (xx, yy).trunc (); //trunc(x/y)。商。divを使うと丸め(RN)で商の絶対値が1大きくなってしまうことがあるのでdivrzを使う
epbQuotient = this.geti32abs ();
epbFpsr |= (epbQuotient & 127) << 16; //商の絶対値の下位7bit
EFP ww = new EFP ();
this.imulw (ww, this, yy).negsub (xx).sub (ww); //x-trunc(x/y)*y。余り。xがyの倍数に近いとき桁落ちが発生するので乗算を倍精度で行う
if (this.flg << 1 < 0) { //余りが0
this.flg = xf | Z; //0にxの符号を付ける
}
}
return this.outer ().finish ();
} else {
this.inner ();
int ye = y.epp; //this==yの場合があるので順序に注意する
long yd = y.dvl;
long yc = y.cvl;
long yc1 = yc >>> 1;
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
int i;
long l;
int q = 0;
if ((i = this.epp - ye) > 0 ||
i == 0 && ((l = this.dvl - yd) > 0L ||
l == 0L && this.cvl >>> 1 >= yc1)) { //|x|>=|y|。商は0ではない
this.flg = P; //|x|。余りの初期値
EFP t = new EFP (P, 0, yd, yc);
do {
t.epp = i = (l = this.dvl - yd) > 0L || l == 0L && this.cvl >>> 1 >= yc1 ? this.epp : this.epp - 1; //指数部を揃えて
if ((i -= ye) <= 31) {
q |= 1 << i;
}
this.sub (t); //引く。アンダーフローのチェックは後で行う
} while (this.flg == 0 && //0ではない
((i = this.epp - ye) > 0 ||
i == 0 && ((l = this.dvl - yd) > 0L ||
l == 0L && this.cvl >>> 1 >= yc1))); //this>=|y|。まだ引ける。指数部が極端に違うと繰り返す回数が大きくなる
this.flg |= xf; //余りが0の場合も含めてyの符号に関係なくxの符号を付ける
} else { //|x|<|y|。商は0
this.flg = xf; //被除数がそのまま余りになる
}
epbQuotient = q;
epbFpsr |= (q & 127) << 16; //商の絶対値の下位7bit
return this.outer ().finish ();
}
} //efp.rem(EFP,EFP)
//------------------------------------------------------------------------
//x = x.rint ()
// x=rint(x)
//y = y.rint (x)
// y=rint(x)
// 丸め(nearest-even)
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{my$x=$_[0];my$t=int$x;my$f=abs($x-$t);$t+($f==0.5&&($t&1)!=0||$f>0.5?$x<=>0:0)});print$g"
// echo read("../misc/efp.gp");eval("rint(x)={my(f=floor(x),s=sign(x-floor(x)-0.5));if(s==0&&(f%2==0)||s<0,f,f+1)}");graph(rint) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+----******
// | | |
// | | |
// | | |
// | | |
// + + *********** +
// | | |
// | | |
// | | |
// | | |
// + + *********** +
// | | |
// | | |
// | | |
// | | |
// + + *********** +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+----***********----+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + *********** + +
// | | |
// | | |
// | | |
// | | |
// + *********** + +
// | | |
// | | |
// | | |
// | | |
// + *********** + +
// | | |
// | | |
// | | |
// | | |
// ******----+---------+---------+---------+---------+---------+---------+---------+
//
// 最も近い整数に丸める
// 小数点以下が0.5のときは偶数の方向に丸める
//
public final EFP rint () {
return this.rint (this);
} //efp.rint()
public final EFP rint (EFP x) { //4.6ns
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
if (xe < 0) { //0<|x|<1
epbFpsr |= EPB_FPSR_X2; //不正確な結果
if (xe < -1 || xd == MSB && xc == 0L) { //0<|x|<=1/2
this.flg = xf | Z; //rint(-1/2<=x<0)=-0, rint(0<x<=1/2)=+0
} else { //1/2<|x|<1
this.flg = xf; //rint(-1<x<-1/2)=-1, rint(1/2<x<1)=1
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
}
return this;
}
//整数部がある
long m = MSB >> xe; //整数部のマスク。符号に注意
if (xe <= 62) { //0..62。dの途中まで整数部
if ((xd & ~m | xc) != 0L) { //小数部が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
long t = xd; //保存して
xd &= m; //小数部を切り捨てる
if ((t & -(m >> 1)) != 0L && (t & (-m | ~(m >> 1)) | xc) != 0L) { //guard bitが1かつLSBまたはguard bit以外の端数が0ではない
xd -= m; //絶対値に1を加える。符号に注意
if (xd >= 0L) { //dから溢れた
xd = MSB;
xe++;
if ((short) xe != xe) { //オーバーフローした
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±Inf
}
}
}
xc = 0L;
}
} else if (xe == 63) { //63。dの末尾まで整数部
if (xc != 0L) { //小数部が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
if (xc < 0L && (xd << -1 | xc << 1) != 0L) { //guard bitが1かつLSBまたはguard bit以外の端数が0ではない
xd++; //絶対値に1を加える
if (xd >= 0L) { //dから溢れた
xd = MSB;
xe++;
if ((short) xe != xe) { //オーバーフローした
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±Inf
}
}
}
xc = 0L;
}
} else if (xe <= LEN - 2) { //64..90。cの途中まで整数部
if ((xc & ~m) != 0L) { //小数部が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
long t = xc; //保存して
xc &= m; //小数部を切り捨てる
if ((t & -(m >> 1)) != 0L && (t & (-m | ~(m >> 1))) != 0L) { //guard bitが1かつLSBまたはguard bit以外の端数が0ではない
xc -= m; //絶対値に1を加える。符号に注意
if ((t ^ xc) < 0L) { //cから溢れた
xd++;
if (xd >= 0L) { //dから溢れた
xd = MSB;
xe++;
if ((short) xe != xe) { //オーバーフローした
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±Inf
}
}
}
}
}
}
//すべて整数部のときはそのまま
return finish (xf, xe, xd, xc, 0L);
} //efp.rint(EFP)
//------------------------------------------------------------------------
//x = x.round ()
//x = x.round (roundingMode)
//x = x.round (x)
//x = x.round (x, roundingMode)
// 丸め
//
// サイズの制限を与えずに整数に丸める
//
public final EFP round () {
return this.round (this, EPB_MODE_RN);
} //efp.round()
public final EFP round (int roundingMode) {
return this.round (this, roundingMode);
} //efp.round(int)
public final EFP round (EFP x) {
return this.round (x, EPB_MODE_RN);
} //efp.round(EFP)
public final EFP round (EFP x, int roundingMode) {
return (roundingMode == EPB_MODE_RN ? this.rint (x) :
roundingMode == EPB_MODE_RM ? this.floor (x) :
roundingMode == EPB_MODE_RP ? this.ceil (x) :
this.trunc (x));
} //efp.round(EFP,int)
//------------------------------------------------------------------------
//x = x.roundd ()
//x = x.roundd (roundingMode)
//x = x.roundd (x)
//x = x.roundd (x, roundingMode)
// double丸め
//
// この関数はepbRoundingModeとepbRoundingPrecを無視する
// double(指数部11bit,仮数部52+1bit,非正規化数を含む)で表現できる値に丸める
// doubleで表現できないときは±Infに変換する
//
public final EFP roundd () {
return this.roundd (this, EPB_MODE_RN);
} //efp.roundd()
public final EFP roundd (int roundingMode) {
return this.roundd (this, roundingMode);
} //efp.roundd(int)
public final EFP roundd (EFP x) {
return this.roundd (x, EPB_MODE_RN);
} //efp.roundd(EFP)
public final EFP roundd (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp; //正規化数は-1022<=xe<=1023、非正規化数は-1075<=xe<=-1023
long xd = x.dvl;
long xc = x.cvl;
if (xe < -1075) { //指数部が小さすぎる。非正規化数の最小値は2^-1074だが丸めで繰り上がる場合があるので一旦2^-1075まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (UNFL_RESULTS[EPB_PREC_DBL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
if (1023 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if ((xd << 53 | xc) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[EPB_PREC_DBL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
long xb = 0L;
int o = xe <= -1023 ? 11 + -1022 - xe : 11; //右にずらすbit数。正規化数は11、非正規化数は11+1<=o<=11+53
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd >>> 53 != 0L) { //繰り上がって溢れたとき
xd = 1L << 52;
xe++; //指数部をインクリメントする。ここでxe=1024になる場合がある
if (1023 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[EPB_PREC_DBL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
} else if (11 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* roundd */
if (xe == -1022) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 52;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
/**/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -1023) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
if (xd == 0L) { //非正規化数でxe==-1075だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_DBL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -1023) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (xd == 0L) { //非正規化数でxe==-1075だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_DBL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
xd <<= Long.numberOfLeadingZeros (xd); //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundd(EFP,int)
//------------------------------------------------------------------------
//x = x.roundf ()
//x = x.roundf (roundingMode)
//y = y.roundf (x)
//y = y.roundf (x, roundingMode)
// float丸め
//
// この関数はepbRoundingModeとepbRoundingPrecを無視する
// float(指数部8bit,仮数部23+1bit,非正規化数を含む)で表現できる値に丸める
// floatで表現できないときは±Infに変換する
//
public final EFP roundf () {
return this.roundf (this, EPB_MODE_RN);
} //efp.roundf()
public final EFP roundf (int roundingMode) {
return this.roundf (this, roundingMode);
} //efp.roundf(int)
public final EFP roundf (EFP x) {
return this.roundf (x, EPB_MODE_RN);
} //efp.roundf(EFP)
public final EFP roundf (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp; //正規化数は-126<=xe<=127、非正規化数は-149<=xe<=-127
long xd = x.dvl;
long xc = x.cvl;
if (xe < -150) { //指数部が小さすぎる。非正規化数の最小値は2^-149だが丸めで繰り上がる場合があるので一旦2^-150まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (UNFL_RESULTS[EPB_PREC_SGL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
if (127 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if ((xd << 24 | xc) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[EPB_PREC_SGL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
long xb = 0L;
int o = xe <= -127 ? 40 + -126 - xe : 40; //右にずらすbit数。正規化数は40、非正規化数は40+1<=o<=40+24
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << -1 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd >>> 24 != 0L) { //繰り上がって溢れたとき
xd = 1L << 23;
xe++; //指数部をインクリメントする。ここでxe=128になる場合がある
if (127 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[EPB_PREC_SGL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
} else if (40 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* roundf */
if (xe == -126) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 23;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
/**/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -127) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
if (xd == 0L) { //非正規化数でxe==-150だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_SGL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -127) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (xd == 0L) { //非正規化数でxe==-150だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_SGL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
}
}
xd <<= Long.numberOfLeadingZeros (xd); //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundf(EFP,int)
//------------------------------------------------------------------------
//x = x.roundg ()
//x = x.roundg (roundingMode)
//y = y.roundg (x)
//y = y.roundg (x, roundingMode)
// xsg丸め
//
// この関数はepbRoundingModeとepbRoundingPrecを無視する
// xsg(指数部15bit,仮数部23+1bit,非正規化数を含む)で表現できる値に丸める
// xsgで表現できないときは±Infに変換する
//
public final EFP roundg () {
return this.roundg (this, EPB_MODE_RN);
} //efp.roundg()
public final EFP roundg (int roundingMode) {
return this.roundg (this, roundingMode);
} //efp.roundg(int)
public final EFP roundg (EFP x) {
return this.roundg (x, EPB_MODE_RN);
} //efp.roundg(EFP)
public final EFP roundg (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp; //正規化数は-16383<=xe<=16383、非正規化数は-16406<=xe<=-16384
long xd = x.dvl;
long xc = x.cvl;
if (xe < -16407) { //指数部が小さすぎる。非正規化数の最小値は2^-16406だが丸めで繰り上がる場合があるので一旦2^-16407まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (UNFL_RESULTS[EPB_PREC_XSG << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
if (16383 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if ((xd << 24 | xc) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[EPB_PREC_XSG << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
long xb = 0L;
int o = xe <= -16384 ? 40 + -16383 - xe : 40; //右にずらすbit数。正規化数は40、非正規化数は40+1<=o<=40+24
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << -1 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd >>> 24 != 0L) { //繰り上がって溢れたとき
xd = 1L << 23;
xe++; //指数部をインクリメントする。ここでxe=16384になる場合がある
if (16383 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[EPB_PREC_XSG << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
} else if (40 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* roundg
if (xe == -16383) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 23;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
*/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
if (xd == 0L) { //非正規化数でxe==-16407だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_XSG << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (xd == 0L) { //非正規化数でxe==-16407だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_XSG << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
}
}
xd <<= Long.numberOfLeadingZeros (xd); //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundg(EFP,int)
//------------------------------------------------------------------------
//x = x.roundi ()
//x = x.roundi (roundingMode)
//x = x.roundi (x)
//x = x.roundi (x, roundingMode)
// int丸め
//
// int(32bit整数)に丸める
// 2^31-1よりも大きい数は2^31-1に、-2^31よりも小さい数は-2^31に変換する(飽和変換)
// NaNは0に変換する
//
public final EFP roundi () {
return this.roundi (this, EPB_MODE_RN);
} //efp.roundi()
public final EFP roundi (int roundingMode) {
return this.roundi (this, roundingMode);
} //efp.roundi(int)
public final EFP roundi (EFP x) {
return this.roundi (x, EPB_MODE_RN);
} //efp.roundi(EFP)
public final EFP roundi (EFP x, int roundingMode) {
return this.seti (x.geti (roundingMode));
} //efp.roundi(EFP,int)
//------------------------------------------------------------------------
//x = x.roundl ()
//x = x.roundl (roundingMode)
//x = x.roundl (x)
//x = x.roundl (x, roundingMode)
// long丸め
//
// long(64bit整数)に丸める
// 2^63-1よりも大きい数は2^63-1に、-2^63よりも小さい数は-2^63に変換する(飽和変換)
// NaNは0に変換する
//
public final EFP roundl () {
return this.roundl (this, EPB_MODE_RN);
} //efp.roundl()
public final EFP roundl (int roundingMode) {
return this.roundl (this, roundingMode);
} //efp.roundl(int)
public final EFP roundl (EFP x) {
return this.roundl (x, EPB_MODE_RN);
} //efp.roundl(EFP)
public final EFP roundl (EFP x, int roundingMode) {
return this.setl (x.getl (roundingMode));
} //efp.roundl(EFP,int)
//------------------------------------------------------------------------
//x = x.roundmand ()
//x = x.roundmand (roundingMode)
//x = x.roundmand (x)
//x = x.roundmand (x, roundingMode)
// 仮数部double丸め
// 仮数部を(1+52)bitに丸める
//
public final EFP roundmand () {
return this.roundmand (this, EPB_MODE_RN);
} //efp.roundmand()
public final EFP roundmand (int roundingMode) {
return this.roundmand (this, roundingMode);
} //efp.roundmand(int)
public final EFP roundmand (EFP x) {
return this.roundmand (x, EPB_MODE_RN);
} //efp.roundmand(EFP)
public final EFP roundmand (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
long xb = 0L;
xb = xc << -11;
xc = xd << -11 | xc >>> 11;
xd >>>= 11;
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd >>> 53 != 0L) { //繰り上がって溢れたとき
xd = 1L << 52;
xe++; //指数部をインクリメントする
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
} //if 端数が0ではない
xd <<= 11; //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundmand(EFP,int)
//------------------------------------------------------------------------
//x = x.roundmanf ()
//x = x.roundmanf (roundingMode)
//y = y.roundmanf (x)
//y = y.roundmanf (x, roundingMode)
// 仮数部float丸め
// 仮数部を(1+23)bitに丸める
//
public final EFP roundmanf () {
return this.roundmanf (this, EPB_MODE_RN);
} //efp.roundmanf()
public final EFP roundmanf (int roundingMode) {
return this.roundmanf (this, roundingMode);
} //efp.roundmanf(int)
public final EFP roundmanf (EFP x) {
return this.roundmanf (x, EPB_MODE_RN);
} //efp.roundmanf(EFP)
public final EFP roundmanf (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
long xb = 0L;
xb = xc << -40;
xc = xd << -40 | xc >>> 40;
xd >>>= 40;
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd >>> 24 != 0L) { //繰り上がって溢れたとき
xd = 1L << 23;
xe++; //指数部をインクリメントする
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
} //if 端数が0ではない
xd <<= 40; //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundmanf(EFP,int)
//------------------------------------------------------------------------
//x = x.roundmanx ()
//x = x.roundmanx (roundingMode)
//x = x.roundmanx (x)
//x = x.roundmanx (x, roundingMode)
// 仮数部extended丸め
// 仮数部を(1+63)bitに丸める
//
public final EFP roundmanx () {
return this.roundmanx (this, EPB_MODE_RN);
} //efp.roundmanx()
public final EFP roundmanx (int roundingMode) {
return this.roundmanx (this, roundingMode);
} //efp.roundmanx(int)
public final EFP roundmanx (EFP x) {
return this.roundmanx (x, EPB_MODE_RN);
} //efp.roundmanx(EFP)
public final EFP roundmanx (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
long xb = 0L;
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd == 0L) { //繰り上がって溢れたとき
xd = MSB;
xe++; //指数部をインクリメントする
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
} //if 端数が0ではない
xd <<= Long.numberOfLeadingZeros (xd); //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundmanx(EFP,int)
//------------------------------------------------------------------------
//x = x.roundmany ()
//x = x.roundmany (roundingMode)
//x = x.roundmany (x)
//x = x.roundmany (x, roundingMode)
// 仮数部triple丸め
// 仮数部を(1+79)bitに丸める
//
public final EFP roundmany () {
return this.roundmany (this, EPB_MODE_RN);
} //efp.roundmany()
public final EFP roundmany (int roundingMode) {
return this.roundmany (this, roundingMode);
} //efp.roundmany(int)
public final EFP roundmany (EFP x) {
return this.roundmany (x, EPB_MODE_RN);
} //efp.roundmany(EFP)
public final EFP roundmany (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
long xb = 0L;
xb = xc << -48;
xc = xd << -48 | xc >>> 48;
xd >>>= 48;
if (xb != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xb < 0L && (xc << 63 | xb << 1) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xc++; //繰り上げる
if (xc == 0L) { //繰り上がって溢れたとき
xd++; //繰り上げる
if (xd >>> 16 != 0L) { //繰り上がって溢れたとき
xd = 1L << 15;
xe++; //指数部をインクリメントする
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
} //if 端数が0ではない
xd = xd << 48 | xc >>> -48;
xc <<= 48; //xbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = xc;
return this;
} //efp.roundmany(EFP,int)
//------------------------------------------------------------------------
//x = x.roundx ()
//x = x.roundx (roundingMode)
//x = x.roundx (x)
//x = x.roundx (x, roundingMode)
// extended丸め
//
// この関数はepbRoundingModeとepbRoundingPrecを無視する
// extended(指数部15bit,仮数部64bit,非正規化数を含む)で表現できる値に丸める
// extendedで表現できないときは±Infに変換する
//
public final EFP roundx () {
return this.roundx (this, EPB_MODE_RN);
} //efp.roundx()
public final EFP roundx (int roundingMode) {
return this.roundx (this, roundingMode);
} //efp.roundx(int)
public final EFP roundx2 (int roundingMode) {
return this.roundx2 (this, roundingMode);
} //efp.roundx(int)
public final EFP roundx (EFP x) {
return this.roundx (x, EPB_MODE_RN);
} //efp.roundx(EFP)
public final EFP roundx (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp; //正規化数は-16383<=xe<=16383、非正規化数は-16446<=xe<=-16384
long xd = x.dvl;
long xc = x.cvl;
if (xe < -16447) { //指数部が小さすぎる。非正規化数の最小値は2^-16446だが丸めで繰り上がる場合があるので一旦2^-16447まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (UNFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
if (16383 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if (xc != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
long xb = 0L;
int o = xe <= -16384 ? 0 + -16383 - xe : 0; //右にずらすbit数。正規化数は0、非正規化数は0+1<=o<=0+64
if (o == 0) {
} else if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd == 0L) { //繰り上がって溢れたとき
xd = MSB;
xe++; //指数部をインクリメントする。ここでxe=16384になる場合がある
if (16383 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
} else if (0 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* roundx
if (xe == -16383) { //非正規化数が繰り上がって正規化数になったとき
//xd = MSB;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
*/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
if (xd == 0L) { //非正規化数でxe==-16447だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (xd == 0L) { //非正規化数でxe==-16447だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
xd <<= Long.numberOfLeadingZeros (xd); //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundx(EFP,int)
public final EFP roundx2 (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp; //正規化数は-16383<=xe<=16383、非正規化数は-16446<=xe<=-16384
long xd = x.dvl;
long xc = x.cvl;
if (xe < -16447) { //指数部が小さすぎる。非正規化数の最小値は2^-16446だが丸めで繰り上がる場合があるので一旦2^-16447まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (UNFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
if (16383 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if (xc != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
long xb = 0L;
int o = xe <= -16384 ? 0 + -16383 - xe : 0; //右にずらすbit数。正規化数は0、非正規化数は0+1<=o<=0+64
if (o == 0) {
} else if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else {
xb = xc;
xc = xd;
xd = 0L;
}
if ((xc | xb) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xc < 0L && (xd << 63 | xc << 1 | xb) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xd++; //繰り上げる
if (xd == 0L) { //繰り上がって溢れたとき
xd = MSB;
xe++; //指数部をインクリメントする。ここでxe=16384になる場合がある
if (16383 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
} else if (0 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* roundx2 */
if (xe == -16383) { //非正規化数が繰り上がって正規化数になったとき
//xd = MSB;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
/**/
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
if (xd == 0L) { //非正規化数でxe==-16447だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (xd == 0L) { //非正規化数でxe==-16447だったとき、先頭の1がxcにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_EXD << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
xd <<= Long.numberOfLeadingZeros (xd); //xcとxbはゴミが残っているので加えないこと
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = 0L;
return this;
} //efp.roundx(EFP,int)
//------------------------------------------------------------------------
//x = x.roundy ()
//x = x.roundy (roundingMode)
//x = x.roundy (x)
//x = x.roundy (x, roundingMode)
// triple丸め
//
// この関数はepbRoundingModeとepbRoundingPrecを無視する
// triple(指数部15bit,仮数部80bit,非正規化数を含む)で表現できる値に丸める
// tripleで表現できないときは±Infに変換する
//
public final EFP roundy () {
return this.roundy (this, EPB_MODE_RN);
} //efp.roundy()
public final EFP roundy (int roundingMode) {
return this.roundy (this, roundingMode);
} //efp.roundy(int)
public final EFP roundy2 (int roundingMode) {
return this.roundy2 (this, roundingMode);
} //efp.roundy(int)
public final EFP roundy (EFP x) {
return this.roundy (x, EPB_MODE_RN);
} //efp.roundy(EFP)
public final EFP roundy (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp; //正規化数は-16383<=xe<=16383、非正規化数は-16462<=xe<=-16384
long xd = x.dvl;
long xc = x.cvl;
if (xe < -16463) { //指数部が小さすぎる。非正規化数の最小値は2^-16462だが丸めで繰り上がる場合があるので一旦2^-16463まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (UNFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
if (16383 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if (xc << 16 != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
long xb = 0L;
long xa = 0L;
int o = xe <= -16384 ? 48 + -16383 - xe : 48; //右にずらすbit数。正規化数は48、非正規化数は48+1<=o<=48+80
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else if (o == 64) {
xb = xc;
xc = xd;
xd = 0L;
} else if (o < 128) {
xa = xc << -o;
xb = xd << -o | xc >>> o;
xc = xd >>> o;
xd = 0L;
} else {
xa = xc;
xb = xd;
xc = 0L;
xd = 0L;
}
if ((xb | xa) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xb < 0L && (xc << 63 | xb << 1 | xa) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xc++; //繰り上げる
if (xc == 0L) { //繰り上がって溢れたとき
xd++; //繰り上げる
if (xd >>> 16 != 0L) { //繰り上がって溢れたとき
//xd = 1L << 15;
xe++; //指数部をインクリメントする。ここでxe=16384になる場合がある
if (16383 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
} //if 指数部が大きすぎる
} else if (48 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* roundy
if (xe == -16383) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 15;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
*/
}
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
if ((xd | xc) == 0L) { //非正規化数でxe==-16463だったとき、先頭の1がxbにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if ((xd | xc) == 0L) { //非正規化数でxe==-16463だったとき、先頭の1がxbにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
if (xd != 0L) {
o = Long.numberOfLeadingZeros (xd);
xd = xd << o | xc >>> -o;
xc <<= o; //xbとxaはゴミが残っているので加えないこと
} else {
xd = xc << Long.numberOfLeadingZeros (xc); //xbとxaはゴミが残っているので加えないこと
xc = 0L;
}
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = xc;
return this;
} //efp.roundy(EFP,int)
public final EFP roundy2 (EFP x, int roundingMode) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp; //正規化数は-16383<=xe<=16383、非正規化数は-16462<=xe<=-16384
long xd = x.dvl;
long xc = x.cvl;
if (xe < -16463) { //指数部が小さすぎる。非正規化数の最小値は2^-16462だが丸めで繰り上がる場合があるので一旦2^-16463まで受け入れる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (UNFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
if (16383 < xe) { //指数部が大きすぎる
if (true) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if (xc << 16 != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
}
} else {
epbFpsr |= EPB_FPSR_OF | EPB_FPSR_X2; //オーバーフロー、不正確な結果
}
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
return this.sete (OVFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
}
long xb = 0L;
long xa = 0L;
int o = xe <= -16384 ? 48 + -16383 - xe : 48; //右にずらすbit数。正規化数は48、非正規化数は48+1<=o<=48+80
if (o < 64) {
xb = xc << -o;
xc = xd << -o | xc >>> o;
xd >>>= o;
} else if (o == 64) {
xb = xc;
xc = xd;
xd = 0L;
} else if (o < 128) {
xa = xc << -o;
xb = xd << -o | xc >>> o;
xc = xd >>> o;
xd = 0L;
} else {
xa = xc;
xb = xd;
xc = 0L;
xd = 0L;
}
if ((xb | xa) != 0L) { //端数が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (roundingMode == EPB_MODE_RN && xb < 0L && (xc << 63 | xb << 1 | xa) != 0L || //RNでguard bitが1かつLSBまたはguard bit以外の端数が0ではないまたは
roundingMode == EPB_MODE_RM && xf < 0 || //端数が0ではなくてRMで-または
roundingMode == EPB_MODE_RP && 0 <= xf) { //端数が0ではなくてRPで+のとき
xc++; //繰り上げる
if (xc == 0L) { //繰り上がって溢れたとき
xd++; //繰り上げる
if (xd >>> 16 != 0L) { //繰り上がって溢れたとき
//xd = 1L << 15;
xe++; //指数部をインクリメントする。ここでxe=16384になる場合がある
if (16383 < xe) { //指数部が大きすぎる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±Inf
} //if 指数部が大きすぎる
} else if (48 < o) { //非正規化数のとき
if (xd << o - 1 < 0L) { //1bit増えたとき
xe++; //指数部をインクリメントする
/* roundy2 */
if (xe == -16383) { //非正規化数が繰り上がって正規化数になったとき
//xd = 1L << 15;
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + xe << 16;
epbExceptionOperandMantissa = xd;
}
/**/
}
}
}
}
//RZ toward zeroのときは端数を切り捨てるだけなので何もしなくてよい
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
if ((xd | xc) == 0L) { //非正規化数でxe==-16463だったとき、先頭の1がxbにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} else { //端数が0
if (xe <= -16384) { //非正規化数
epbFpsr |= EPB_FPSR_UF; //アンダーフロー
epbExceptionOperandExponent = x.flg & M | 0x3fff + 0x6000 + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if ((xd | xc) == 0L) { //非正規化数でxe==-16463だったとき、先頭の1がxbにあって丸めで繰り上がらなかった
return this.sete (UNFL_RESULTS[EPB_PREC_TPL << 3 | roundingMode << 1 | xf >>> 31]); //±0
}
} //if 非正規化数
} //if 端数が0ではない/端数が0
if (xd != 0L) {
o = Long.numberOfLeadingZeros (xd);
xd = xd << o | xc >>> -o;
xc <<= o; //xbとxaはゴミが残っているので加えないこと
} else {
xd = xc << Long.numberOfLeadingZeros (xc); //xbとxaはゴミが残っているので加えないこと
xc = 0L;
}
//結果
this.flg = xf;
this.epp = xe;
this.dvl = xd;
this.cvl = xc;
return this;
} //efp.roundy(EFP,int)
//------------------------------------------------------------------------
//x = x.scale (y)
// x*=2^trunc(y)
//z = z.scale (x, y)
// z=x*2^trunc(y)
// 2^trunc(y)倍
//
public final EFP scale (EFP y) {
return this.scale (this, y);
} //efp.scale(EFP)
public final EFP scale (EFP x, EFP y) {
int xf = x.flg;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf | yf) << 3 < 0) { //どちらかがNaN
this.flg = N;
} else if (yf << 1 < 0) { //scale(±0,±0)=±0, scale(±Inf,±0)=±Inf, scale(±x,±0)=±x
this.finish (x.flg, x.epp, x.dvl, x.cvl, 0L);
} else if (yf << 2 < 0) { //scale(±0,±Inf)=NaN,OE, scale(±Inf,±Inf)=NaN,OE, scale(±x,±Inf)=NaN,OE
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N;
} else if (xf << 1 < 0) { //scale(±0,±y)=±0
this.flg = xf;
} else if (xf << 2 < 0) { //scale(±Inf,±y)=±Inf
this.flg = xf;
}
return this;
}
//両方±0,±Inf,NaN以外
// スケールをround-to-zeroで整数にする
// geti()は飽和変換だが飽和させるとオペランドエラーがセットされてしまうので先に範囲を確認する
int i = (16 <= y.epp ? yf < 0 ? -1 << 16 : 1 << 16 : //スケールの絶対値が2^16以上
y.geti ());
if (i <= -1 << 14) { //スケールが-2^14以下のとき常にアンダーフロー。MC68882に合わせる
epbFpsr |= EPB_FPSR_UF | EPB_FPSR_X2; //アンダーフロー、不正確な結果
if (i <= -1 << 16) { //スケールが-2^16以下
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = x.dvl;
} else {
epbExceptionOperandExponent = xf | 0x3fff + 0x6000 + i << 16;
epbExceptionOperandMantissa = x.dvl;
}
return this.sete (UNFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±0
}
if (1 << 14 <= i) { //スケールが2^14以上のとき常にオーバーフロー。MC68882に合わせる
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
if (1 << 16 <= i) { //スケールが2^16以上
epbExceptionOperandExponent = xf;
epbExceptionOperandMantissa = x.dvl;
} else {
epbExceptionOperandExponent = xf | 0x3fff - 0x6000 + i << 16;
epbExceptionOperandMantissa = x.dvl;
}
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±Inf
}
return this.finish2 (xf, x.epp + i, x.dvl, x.cvl, 0L); //スケールを加える
} //efp.scale(EFP,EFP)
//------------------------------------------------------------------------
//x = x.sec ()
// x=sec(x)
//y = y.sec (x)
// y=sec(x)
// 正割 secant セカント
//
// グラフ
// perl -e "use Math::Trig;use Graph;$g=new Graph();$g->grid();$g->func(sub{sec($_[0])});print$g"
// echo read("../misc/efp.gp");eval("sec(x)=1/cos(x)");graph(sec) | gp -q
// +---------+---------+------*--+---------+---------+--*------+---------+---------+
// | * | * |
// | * | * |
// | * | * |
// | ** | ** |
// + * + * +
// | * | * |
// | * | * |
// | ** | ** |
// | * | * |
// + ** + ** +
// | ** | ** |
// | ** | ** |
// | ** | ** |
// | **** | **** |
// + ********* +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + ********** + ********** +
// | *** **** | **** *** |
// *** ** | ** ***
// * ** | ** *
// | ** | ** |
// + * + * +
// | ** | ** |
// | * | * |
// | * | * |
// | ** | ** |
// + * + * +
// | * | * |
// | * | * |
// | ** | ** |
// | * | * |
// +---------+---------+-*-------+---------+---------+-------*-+---------+---------+
//
// 三角関数との関係
// sec(x)=1/cos(x)
//
public final EFP sec () {
return this.sec (this);
} //efp.sec()
public final EFP sec (EFP x) {
return this.inner ().cos (x).outer ().rcp (); //1/cos(x)
} //efp.sec(EFP)
//------------------------------------------------------------------------
//x = x.sech ()
// x=sech(x)
//y = y.sech (x)
// y=sech(x)
// 双曲線正割 hyperbolic secant ハイパボリックセカント
//
// グラフ
// perl -e "use Math::Trig;use Graph;$g=new Graph();$g->grid();$g->func(sub{sech($_[0])});print$g"
// echo read("../misc/efp.gp");eval("sech(x)=1/cosh(x)");graph(sech) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + *********** +
// | ***** | ***** |
// | ***** | ***** |
// | ******* | ******* |
// | ************ | ************ |
// ***********---------+---------+---------+---------+---------+---------***********
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
// 双曲線関数との関係
// sech(x)=1/cosh(x)
//
// 指数関数との関係
// sech(x)=2/(e^x+e^-x)
// =2*e^x/((e^x)^2+1)
//
public final EFP sech () {
return this.sech (this);
} //efp.sech()
public final EFP sech (EFP x) {
return this.inner ().cosh (x).outer ().rcp (); //1/cosh(x)
} //efp.sech(EFP)
//------------------------------------------------------------------------
//y = y.set0 ()
// +0代入
//
public final EFP set0 () {
this.flg = P | Z;
//this.epp = 0;
//this.dvl = 0L;
//this.cvl = 0L;
return this;
} //efp.set0()
//------------------------------------------------------------------------
//y = y.set1 ()
// +1代入
//
public final EFP set1 () {
this.flg = P;
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
return this;
} //efp.set1()
//------------------------------------------------------------------------
//y = y.setapery ()
// y=ζ(3)
// アペリーの定数 Apéry's constant
//
// 式
// ζ(3)=sum[n=1..∞]{1/n^3}
//
// 値
// echo read("../misc/efp.gp");printf("%.100g\n",zeta(3)) | gp -q
// 1.202056903159594285399738161511449990764986292340498881792271555341838205786313090186455873609335258
//
// 参考
// https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%9A%E3%83%AA%E3%83%BC%E3%81%AE%E5%AE%9A%E6%95%B0
// https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%9A%E3%83%AA%E3%83%BC%E3%81%AE%E5%AE%9A%E7%90%86
// https://en.wikipedia.org/wiki/Ap%C3%A9ry%27s_constant
// http://society.math.ntu.edu.tw/~journal/tjm/V4N4/tjm0012_3.pdf
// http://www.numberworld.org/digits/Zeta(3)/
//
public final EFP setapery () {
epbFpsr |= EPB_FPSR_X2; //不正確な結果
return this.sete (ROUNDED_APERY[epbRoundingMode]).finish ();
} //efp.setapery()
//------------------------------------------------------------------------
//y = y.setcatalan ()
// y=G
// カタランの定数 Catalan's_constant
//
// 式
// G=beta(2)
// =sum[n=0..∞]{(-1)^n/(2*n+1)^2}
// =1/1^2-1/3^2+1/5^2-1/7^2+1/9^2-1/11^2+1/13^2-1/15^2+1/17^2-1/19^2+...
//
// 値
// echo read("../misc/efp.gp");printf("%.100g\n",Catalan) | gp -q
// 0.9159655941772190150546035149323841107741493742816721342664981196217630197762547694793565129261151062
//
// 参考
// https://en.wikipedia.org/wiki/Catalan%27s_constant
// http://www.numberworld.org/digits/Catalan/
//
public final EFP setcatalan () {
epbFpsr |= EPB_FPSR_X2; //不正確な結果
return this.sete (ROUNDED_CATALAN[epbRoundingMode]).finish ();
} //efp.setcatalan()
//------------------------------------------------------------------------
//y = y.setd (d)
//y = y.setd01 (b, a)
//y = y.setd01 (ib, ia)
//y = y.setd01 (l)
// double代入
// 丸め処理を行わない
//
public final EFP setd (double d) {
return setd01 (Double.doubleToLongBits (d));
} //efp.setd(double)
public final EFP setd01 (byte[] b, int a) {
return setd01 ((long) b[a] << 56 |
(long) (0xff & b[a + 1]) << 48 |
(long) (0xff & b[a + 2]) << 40 |
(long) (0xff & b[a + 3]) << 32 |
(long) (0xff & b[a + 4]) << 24 |
(long) (0xff & b[a + 5]) << 16 |
(long) (0xff & b[a + 6]) << 8 |
(long) (0xff & b[a + 7]));
} //efp.setd01(byte[],int)
public final EFP setd01 (int[] ib, int ia) {
return setd01 ((long) ib[ia] << 32 |
(0xffffffffL & ib[ia + 1]));
} //efp.setd012(int[],int)
public final EFP setd01 (long l) {
int zf = (int) (l >>> 32) & M; //符号
int ze = ((int) (l >>> 52) & 0x7ff) - 1023; //指数部
long zd = 0L;
l &= -1L >>> 12; //仮数部の小数部。doubleは正規化されているとき整数部が省略されているので後で先頭に1を付け足す必要がある
if (ze == 1024) { //±Inf,NaN
if (l == 0L) { //±Inf
zf |= I;
} else { //NaN
if (l << 12 >= 0L) { //SNaN
epbFpsr |= EPB_FPSR_SN; //シグナリングNaN
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xbfffffffffffffffL;
}
zf = N;
}
} else if (ze >= -1022) { //正規化数
zd = MSB | l << 11; //整数部の1を付け足す
} else if (l == 0L) { //±0
zf |= Z;
} else { //非正規化数
int o = Long.numberOfLeadingZeros (l);
ze -= o - 12;
zd = l << o; //非正規化数は整数部が存在しない
}
this.flg = zf;
this.epp = ze;
this.dvl = zd;
this.cvl = 0L;
//非正規化数でもアンダーフロー(UF)をセットしない
//丸めない
return this;
} //efp.setd01(long)
//------------------------------------------------------------------------
//y = y.sete (x)
// y=x
// EFP代入
// コピーするだけ
// 丸め処理を行わない
//
public final EFP sete (EFP x) {
this.flg = x.flg;
this.epp = x.epp;
this.dvl = x.dvl;
this.cvl = x.cvl;
return this;
} //efp.sete(EFP)
//------------------------------------------------------------------------
//y = y.seteuler ()
// y=γ
// オイラー・マスケローニ定数 Euler-Mascheroni constant
//
// 式
// γ=lim[n→∞]{sum[k=1..∞]{1/k}-log(n)}
//
// 値
// echo read("../misc/efp.gp");printf("%.100g\n",Euler) | gp -q
// 0.5772156649015328606065120900824024310421593359399235988057672348848677267776646709369470632917467495
//
// 参考
// https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%A4%E3%83%A9%E3%83%BC%E3%81%AE%E5%AE%9A%E6%95%B0
// https://en.wikipedia.org/wiki/Euler%E2%80%93Mascheroni_constant
// http://www.numberworld.org/digits/EulerGamma/
//
public final EFP seteuler () {
epbFpsr |= EPB_FPSR_X2; //不正確な結果
return this.sete (ROUNDED_EULER[epbRoundingMode]).finish ();
} //efp.seteuler()
//------------------------------------------------------------------------
//y = y.setf (f)
//y = y.setf0 (b, a)
//y = y.setf0 (ib, ia)
//y = y.setf0 (i)
// float代入
// 丸め処理を行わない
//
public final EFP setf (float f) {
return setf0 (Float.floatToIntBits (f));
} //efp.setf(float)
public final EFP setf0 (byte[] b, int a) {
return setf0 (b[a] << 24 |
(0xff & b[a + 1]) << 16 |
(0xff & b[a + 2]) << 8 |
(0xff & b[a + 3]));
} //efp.setf0(byte[],int)
public final EFP setf0 (int[] ib, int ia) {
return setf0 (ib[ia]);
} //efp.setf0(int[],int)
public final EFP setf0 (int i) {
int zf = i & M; //符号
int ze = (i >>> 23 & 0xff) - 127; //指数部
long zd = 0L;
i &= -1 >>> 9; //仮数部の小数部。floatは正規化されているとき整数部が省略されているので後で先頭に1を付け足す必要がある
if (ze == 128) { //±Inf,NaN
if (i == 0) { //±Inf
zf |= I;
} else { //NaN
if (i << 9 >= 0) { //SNaN
epbFpsr |= EPB_FPSR_SN; //シグナリングNaN
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xbfffffffffffffffL;
}
zf = N;
}
} else if (ze >= -126) { //正規化数
zd = (long) (1 << 23 | i) << 32 + 8; //整数部の1を付け足す
} else if (i == 0) { //±0
zf |= Z;
} else { //非正規化数
int o = Integer.numberOfLeadingZeros (i);
ze -= o - 9;
zd = (long) i << 32 + o; //非正規化数は整数部が存在しない
}
this.flg = zf;
this.epp = ze;
this.dvl = zd;
this.cvl = 0L;
//非正規化数でもアンダーフロー(UF)をセットしない
//丸めない
return this;
} //efp.setf0(float)
//------------------------------------------------------------------------
//y = y.seti (i)
// int代入
//
public final EFP seti (int i) {
if (i == 0) {
this.flg = P | Z; //+0
return this;
}
int zf = P;
if (i < 0) { //x<0
zf = M;
i = -i;
}
int ze = 31 - Integer.numberOfLeadingZeros (i);
long zd = (long) i << 63 - ze; //0x80000000のとき1拡張になるが余分な1は押し出されるのでマスクは不要
return this.finish (zf, ze, zd, 0L, 0L);
} //efp.seti(int)
//------------------------------------------------------------------------
//y = y.setinf ()
// +Inf代入
//
public final EFP setinf () {
this.flg = P | I;
//this.epp = 0;
//this.dvl = 0L;
//this.cvl = 0L;
return this;
} //efp.setinf()
//------------------------------------------------------------------------
//y = y.setl (l)
// long代入
//
public final EFP setl (long l) {
if (l == 0L) {
this.flg = P | Z; //+0
return this;
}
int zf = P;
if (l < 0L) { //x<0
zf = M;
l = -l;
}
int ze = 63 - Long.numberOfLeadingZeros (l);
long zd = l << ~ze;
return this.finish (zf, ze, zd, 0L, 0L);
} //efp.setl(long)
//------------------------------------------------------------------------
//y = y.setmax ()
// 最大値代入
//
// +Infの次に大きい表現可能な値
//
public final EFP setmax () {
return this.finish (P, 32767, 0xffffffffffffffffL, 0xffffffffffffffffL << 128 - LEN, 0L);
} //efp.setmax()
//------------------------------------------------------------------------
//y = y.setmin ()
// 最小値代入
//
// -Infの次に小さい表現可能な値
//
public final EFP setmin () {
return this.finish (M, -32767, MSB, 0L, 0L);
} //efp.setmin()
//------------------------------------------------------------------------
//y = y.setnan ()
// NaN代入
//
public final EFP setnan () {
this.flg = N;
//this.epp = 0;
//this.dvl = 0L;
//this.cvl = 0L;
return this;
} //efp.setnan()
//------------------------------------------------------------------------
//y = y.setnapier ()
// y=e
// ネイピア数 Napier's constant
//
// 式
// e=sum[n=0..∞]{1/n!}
//
// 値
// echo read("../misc/efp.gp");printf("%.100g\n",exp(1)) | gp -q
// 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427
//
// 参考
// https://ja.wikipedia.org/wiki/%E3%83%8D%E3%82%A4%E3%83%94%E3%82%A2%E6%95%B0
// https://en.wikipedia.org/wiki/E_(mathematical_constant)
// http://www.numberworld.org/digits/E/
//
public final EFP setnapier () {
epbFpsr |= EPB_FPSR_X2; //不正確な結果
return this.sete (ROUNDED_NAPIER[epbRoundingMode]).finish ();
} //efp.setnapier()
//------------------------------------------------------------------------
//y = y.setp012 (b, a)
//y = y.setp012 (ib, ia)
//y = y.setp012 (i, l)
// packed代入
//
public final EFP setp012 (byte[] b, int a) {
return setp012 (b[a] << 24 |
(0xff & b[a + 1]) << 16 |
(0xff & b[a + 2]) << 8 |
(0xff & b[a + 3]),
(long) b[a + 4] << 56 |
(long) (0xff & b[a + 5]) << 48 |
(long) (0xff & b[a + 6]) << 40 |
(long) (0xff & b[a + 7]) << 32 |
(long) (0xff & b[a + 8]) << 24 |
(long) (0xff & b[a + 9]) << 16 |
(long) (0xff & b[a + 10]) << 8 |
(long) (0xff & b[a + 11]));
} //efp.setp012(byte[],int)
public final EFP setp012 (int[] ib, int ia) {
return setp012 (ib[ia],
(long) ib[ia + 1] << 32 |
(0xffffffffL & ib[ia + 2]));
} //efp.setp012(int[],int)
public final EFP setp012 (int u, long v) {
int zf = u & M; //仮数部の符号
int e = XEiJ.FMT_DCB4[u >>> 16 & 0xfff]; //指数部
int m0 = XEiJ.FMT_DCB4[u & 0x000f]; //整数部
int m1 = XEiJ.FMT_DCB4[(char) (v >>> 48)]; //小数部
int m2 = XEiJ.FMT_DCB4[(char) (v >>> 32)];
int m3 = XEiJ.FMT_DCB4[(char) (v >>> 16)];
int m4 = XEiJ.FMT_DCB4[(char) v ];
{
int t = m0 | m1 | m2 | m3 | m4;
if ((u & 0x30000000) != 0 || //±Inf,NaN
(e | t) < 0) { //BCDに0..9以外の文字がある
if (v == 0L) { //±Inf
this.flg = zf | I;
} else { //NaN
if (v << 1 >= 0L) { //SNaN
epbFpsr |= EPB_FPSR_SN; //シグナリングNaN
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xbfffffffffffffffL;
}
this.flg = N;
}
return this;
}
if (t == 0) { //整数部と小数部がすべて0
this.flg = zf | Z; //±0
return this;
}
}
//±0,±Inf,NaN以外
//FPSRを保存する
int savedMode = epbRoundingMode;
int savedFpsr = epbFpsr;
epbFpsr = 0;
//仮数部を変換する
this.inner ();
EFP t = new EFP ();
this.setl ((long) (m0 * 100000000 + m1 * 10000 + m2)).imul (TENXP3).iadd (t.setl ((long) (m3 * 10000 + m4))); //仮数部
//符号を付ける
// 符号を付けてから丸めないとRMとRPが逆になってしまう
this.flg |= zf;
//指数部を変換する
if (u << 1 < 0) { //指数部の符号
e = -e;
}
e -= 16; //小数点以下の桁数
if (e < 0) { //10^-eで割る
e = -e;
t.set1 ();
for (int i = 0; e != 0; i++, e >>>= 1) {
if ((e & 1) != 0) {
t.imul (EFP_TEN_POWER_P[i]);
}
}
epbRoundingPrec = EPB_PREC_EXD;
epbRoundingMode = savedMode;
this.div (t);
} else { //10^eを掛ける
t.set1 ();
for (int i = 0; e != 0; i++, e >>>= 1) {
if ((e & 1) != 0) {
t.imul (EFP_TEN_POWER_P[i]);
}
}
epbRoundingPrec = EPB_PREC_EXD;
epbRoundingMode = savedMode;
this.mul (t);
}
this.outer ();
//基数変換で生じたX2をX1に移す
epbFpsr = savedFpsr | epbFpsr >>> 1 & EPB_FPSR_X1;
//丸める
// 丸めで生じたOF,UF,X2はそのまま返す
return this.finish ();
} //efp.setp012(int,long)
//------------------------------------------------------------------------
//y = y.setpi ()
// y=pi
// 円周率
//
// 式
// Fast multiple-precision evaluation of elementary functions (1976)
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.98.4721
// A=1
// B=2^(-1/2)
// T=1/4
// X=1
// while A-B>2^(-n) {
// Y=A
// A=(A+B)/2
// B=sqrt(B*Y)
// T=T-X*(A-Y)^2
// X=2*X
// }
// return A^2/T [or, better, (A+B)^2/(4*T)]
//
// AGMアルゴリズム
// http://www.kurims.kyoto-u.ac.jp/~ooura/pi_fft-j.html
// ---- a formula based on the AGM (Arithmetic-Geometric Mean) ----
// c = sqrt(0.125);
// a = 1 + 3 * c;
// b = sqrt(a);
// e = b - 0.625;
// b = 2 * b;
// c = e - c;
// a = a + e;
// npow = 4;
// do {
// npow = 2 * npow;
// e = (a + b) / 2;
// b = sqrt(a * b);
// e = e - b;
// b = 2 * b;
// c = c - e;
// a = e + b;
// } while (e > SQRT_SQRT_EPSILON);
// e = e * e / 4;
// a = a + b;
// pi = (a * a - e - e / 2) / (a * c - e) / npow;
// ---- modification ----
// This is a modified version of Gauss-Legendre formula
// (by T.Ooura). It is faster than original version.
//
// 値
// echo read("../misc/efp.gp");printf("%.100g\n",Pi) | gp -q
// 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
//
// 参考
// https://ja.wikipedia.org/wiki/%E5%86%86%E5%91%A8%E7%8E%87
// https://en.wikipedia.org/wiki/Pi
// http://www.numberworld.org/digits/Pi/
//
public final EFP setpi () {
epbFpsr |= EPB_FPSR_X2; //不正確な結果
return this.sete (ROUNDED_PI[epbRoundingMode]).finish ();
} //efp.setpi()
//------------------------------------------------------------------------
//y = y.setx012 (b, a)
//y = y.setx012 (ib, ia)
//y = y.setx012 (i, l)
// extended代入
// 丸め処理を行わない
//
public final EFP setx012 (byte[] b, int a) {
return setx012 (b[a] << 24 |
(0xff & b[a + 1]) << 16 |
(0xff & b[a + 2]) << 8 |
(0xff & b[a + 3]),
(long) b[a + 4] << 56 |
(long) (0xff & b[a + 5]) << 48 |
(long) (0xff & b[a + 6]) << 40 |
(long) (0xff & b[a + 7]) << 32 |
(long) (0xff & b[a + 8]) << 24 |
(long) (0xff & b[a + 9]) << 16 |
(long) (0xff & b[a + 10]) << 8 |
(long) (0xff & b[a + 11]));
} //efp.setx012(byte[],int)
public final EFP setx012 (int[] ib, int ia) {
return setx012 (ib[ia],
(long) ib[ia + 1] << 32 |
(0xffffffffL & ib[ia + 2]));
} //efp.setx012(int[],int)
public final EFP setx012 (int i, long l) {
int zf = i & M; //符号
int ze = (i >>> 16 & 32767) - 16383; //指数部
if (ze == 16384) { //±Inf,NaN
if (l == 0L) { //±Inf
this.flg = zf | I;
} else { //NaN
if (l << 1 >= 0L) { //SNaN
epbFpsr |= EPB_FPSR_SN; //シグナリングNaN
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xbfffffffffffffffL;
}
this.flg = N;
}
return this;
}
if (l == 0L) { //±0
this.flg = zf | Z;
return this;
}
if (l >= 0L) { //未正規化数または非正規化数
int o = Long.numberOfLeadingZeros (l); //1..63
ze -= o;
l <<= o;
}
this.flg = zf;
this.epp = ze;
this.dvl = l;
this.cvl = 0L;
//非正規化数でもアンダーフロー(UF)をセットしない
//丸めない
return this;
} //efp.setx012(int,long)
//------------------------------------------------------------------------
//y = y.sety012 (b, a)
//y = y.sety012 (ib, ia)
//y = y.sety012 (i, l)
// triple代入
// 丸め処理を行わない
//
public final EFP sety012 (byte[] b, int a) {
return sety012 (b[a] << 24 |
(0xff & b[a + 1]) << 16 |
(0xff & b[a + 2]) << 8 |
(0xff & b[a + 3]),
(long) b[a + 4] << 56 |
(long) (0xff & b[a + 5]) << 48 |
(long) (0xff & b[a + 6]) << 40 |
(long) (0xff & b[a + 7]) << 32 |
(long) (0xff & b[a + 8]) << 24 |
(long) (0xff & b[a + 9]) << 16 |
(long) (0xff & b[a + 10]) << 8 |
(long) (0xff & b[a + 11]));
} //efp.sety012(byte[],int)
public final EFP sety012 (int[] ib, int ia) {
return sety012 (ib[ia],
(long) ib[ia + 1] << 32 |
(0xffffffffL & ib[ia + 2]));
} //efp.sety012(int[],int)
public final EFP sety012 (int i, long l) {
int zf = i & M; //符号
int ze = (i >>> 16 & 32767) - 16383; //指数部
if (ze == 16384) { //±Inf,NaN
if (l == 0L) { //±Inf
this.flg = zf | I;
} else { //NaN
if (l << 1 >= 0L) { //SNaN
epbFpsr |= EPB_FPSR_SN; //シグナリングNaN
epbExceptionOperandExponent = 0x7fff << 16;
epbExceptionOperandMantissa = 0xbfffffffffffffffL;
}
this.flg = N;
}
return this;
}
long m = (long) i << 48; //仮数部の下位16bit
if (l == 0L && m == 0L) { // //±0
this.flg = zf | Z;
return this;
}
if (l >= 0L) { //未正規化数または非正規化数
if (l != 0L) {
int o = Long.numberOfLeadingZeros (l); //1..63
ze -= o;
l = l << o | m >>> -o;
m <<= o;
} else {
int o = 64 + Long.numberOfLeadingZeros (m); //64..79
ze -= o;
l = m << o;
m = 0L;
}
}
this.flg = zf;
this.epp = ze;
this.dvl = l;
this.cvl = m;
//非正規化数でもアンダーフロー(UF)をセットしない
//丸めない
return this;
} //efp.sety012(int,long)
//------------------------------------------------------------------------
//x = x.sgn ()
// x=x<=>0
//y = y.sgn (x)
// y=x<=>0
// 符号
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{$_[0]<=>0});print$g"
// echo read("../misc/efp.gp");graph(sign) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + *****************************************
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------*---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// ***************************************** +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
// isNaN(x)||x==0?x:x>0?1:-1
//
// NaNの扱い
// NaNのときはNaNを返す
//
// ±0の扱い
// ±0のときは±0を符号を付けたまま返す
//
public final EFP sgn () {
return this.sgn (this);
} //efp.sgn()
public final EFP sgn (EFP x) {
int xf = x.flg;
if ((xf & (Z | N)) != 0) { //±0,NaN
this.flg = xf;
} else { //±0,NaN以外
this.flg = xf & M; //sgn(±Inf)=±1,sgn(±x)=±1
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
}
return this;
} //efp.sgn(EFP)
//------------------------------------------------------------------------
//x = x.sgnsub (y)
// x=x<=>y
//z = z.sgnsub (x, y)
// z=x<=>y
// 比較
//
// -Inf<-x<-0==+0<+x<+Inf
//
// x.sub(y).sgn()と同じ結果を短い時間で返す
// 仮数部を比較する必要があるのはフラグと指数部が一致している場合だけ
// 仮数部を比較する場合も減算結果を正規化する必要がない
//
// 結果をbooleanで返す関数の代用にはならないことに注意
// z.sgnsub(x,y)がNaNを返すとき結果をbooleanで返す関数ではtrueにしなければならない場合とfalseにしなければならない場合がある
//
// NaNの扱い
// どちらかがNaNのときはNaNを返す
// x.cmp(y)はどちらかがNaNのときに0を返す
//
// ±Infの扱い
// +Inf<=>+Infまたは-Inf<=>-InfのときはNaNを返す
//
// ±0の扱い
// 両方が±0のときは符号に関係なく+0を返す
//
// メモ
// EFPではインスタンスのフラグがコンディションコードを兼ねているので純粋にコンディションコードだけを返すメソッドは作れない
// フラグを書き換えると値が変わってしまう
//
public final EFP sgnsub (EFP y) {
return this.sgnsub (this, y);
} //efp.sgnsub(EFP)
public final EFP sgnsub (EFP x, EFP y) {
int xf = x.flg;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf & yf) << 1 < 0 && xf == yf) { //両方±0で符号が同じとき+0
this.flg = P | Z;
} else if ((xf & yf) << 2 < 0 && xf == yf || //両方±Infで符号が同じときNaN
(xf | yf) << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
} else if ((xf << 1 | yf << 2) < 0) { //xが±0またはyが±Infのときsgn(-y)
if (yf << 1 < 0) {
this.flg = yf ^ M;
} else {
this.flg = yf & M ^ M;
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
}
} else { //xが±Infまたはyが±0のときsgn(x)
this.flg = xf & M;
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
}
} else if (xf != yf) { //両方±0,±Inf,NaN以外で符号が違う
this.flg = xf >= 0 ? P : M;
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
} else { //両方±0,±Inf,NaN以外で符号が同じ
int s;
long t;
s = (xf >= 0 ? 1 : -1) * ((s = x.epp - y.epp) != 0 ? s >= 0 ? 1 : -1 :
(t = x.dvl - y.dvl) != 0L ? t >= 0L ? 1 : -1 :
(t = (x.cvl >>> 1) - (y.cvl >>> 1)) != 0L ? t >= 0L ? 1 : -1 :
0);
if (s != 0) { //値が違う
this.flg = s >= 0 ? P : M;
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
} else { //値が同じ
this.flg = P | Z; //+0
}
}
return this;
} //efp.sgnsub(EFP,EFP)
//------------------------------------------------------------------------
//x = x.shl (n)
// x*=2^n
//y = y.shl (x, n)
// y=x*2^n
// 2^n倍(左シフト)
//
public final EFP shl (int n) {
//nが大きすぎてInteger.MAX_VALUEを跨いでしまうと都合が悪いのでnに細工をする
n = Math.max (-65536, Math.min (65536, n));
return this.finish (this.flg, this.epp + n, this.dvl, this.cvl, 0L);
} //efp.shl(int)
public final EFP shl (EFP x, int n) {
//nが大きすぎてInteger.MAX_VALUEを跨いでしまうと都合が悪いのでnに細工をする
n = Math.max (-65536, Math.min (65536, n));
return this.finish (x.flg, x.epp + n, x.dvl, x.cvl, 0L);
} //efp.shl(EFP,int)
//------------------------------------------------------------------------
//x = x.shr (n)
// x/=2^n
//y = y.shr (x, n)
// y=x/2^n
// 1/2^n倍(右シフト)
//
public final EFP shr (int n) {
//nが大きすぎてInteger.MAX_VALUEを跨いでしまうと都合が悪いのでnに細工をする
n = Math.max (-65536, Math.min (65536, n));
return this.finish (this.flg, this.epp - n, this.dvl, this.cvl, 0L);
} //efp.shr(int)
public final EFP shr (EFP x, int n) {
//nが大きすぎてInteger.MAX_VALUEを跨いでしまうと都合が悪いのでnに細工をする
n = Math.max (-65536, Math.min (65536, n));
return this.finish (x.flg, x.epp - n, x.dvl, x.cvl, 0L);
} //efp.shr(EFP,int)
//------------------------------------------------------------------------
//x = x.sin ()
// x=sin(x)
//y = y.sin (x)
// y=sin(x)
// 正弦 sine サイン
//
// グラフ
// perl -e "use Math::Trig;use Graph;$g=new Graph();$g->grid();$g->func(sub{sin($_[0])});print$g"
// echo read("../misc/efp.gp");graph(sin) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + ********** +
// ** | **** ***** |
// |*** | **** *** |
// | **** | *** *** |
// | *** |*** *** |
// +-------***---------+---------+--------***--------+---------+---------***-------+
// | *** ***| *** |
// | *** *** | **** |
// | *** **** | ***|
// | ***** **** | **
// + ********** + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
// 定義域
// -inf<=x<=inf
//
// 値域
// -1<=sin(x)<=1
//
// 三角関数のとの関係
// sin(x)=2*tan(x/2)/(1+tan(x/2)^2)
//
// 変数変換
// 収束を速くするために|x|<=pi/4にする
// sin(x)=cos(x-pi/2)
// =-sin(x-pi)
// =-cos(x-3*pi/2)
// =sin(x-2*pi)
// cos(x-pi/2)
// k=1
// │ ←
// k=2↓\ │ /
// \ │ /
// \│/
// -sin(x-pi) ────・──── sin(x)
// /│\
// / │ \
// / │ \↑k=0
// → │
// k=3
// -cos(x-3*pi/2)
//
// テイラー展開
// sin(x)=x-x^3/3!+x^5/5!-x^7/7!...
// f(n,x)=sum(k=0,n,(-1)^k*x^(2*k+1)/(2*k+1)!)
// 除算は不要
//
// チェビシェフ展開
// テイラー展開よりも収束が速い
// 除算は不要
//
// CORDIC
// 固定小数点演算用
// 浮動小数点演算では結果の指数部が小さいとき有効桁数が不足する
// 桁数の少ない浮動小数点演算では加減算と乗算のコストがあまり変わらないので乗算が減っても加減算が増え過ぎるとかえって遅くなる
// 参考
// サルでも分かるCORDICアルゴリズム
// http://teamcoil.sp.u-tokai.ac.jp/calculator/100224/
//
// sin(x)
// echo read("../misc/efp.gp");eval("f(n,x)=sum(k=0,n,(-1)^k/(2*k+1)!*x^(2*k+1))");for(n=0,26,printf("%4d",floor(closeness(sin,f(n,x),-Pi/4,Pi/4,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=sin(x)");a=-Pi/4;b=-a;forstep(n=1,27,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// 次数 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53
// テイラー展開 3 8 14 21 28 36 44 53 62 72 81 91 102 112 122 133 144 155 166 178 189 201 213 225 237 249 261
// チェビシェフ展開
// [-pi/4,pi/4] 3 10 17 26 35 45 55 65 76 88 99 111 123 135
//
public final EFP sin () {
return this.sin (this);
} //efp.sin()
public final EFP sin (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
this.flg = xf; //sin(±0)=±0
} else if (xf << 2 < 0) { //±Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N; //sin(±Inf)=NaN
} else { //NaN
this.flg = N; //sin(NaN)=NaN
}
return this;
}
//±0,±Inf,NaN以外
int savedFpsr = epbFpsr;
this.inner ();
if (this == x) {
x = new EFP (x);
}
EFP u = new EFP ();
EFP u2 = new EFP ();
int k = u.ieeerempi2 (x); //-pi/2<=u<=pi/2。kはx-uの象限
if (false) { //テイラー展開
EFP s = new EFP ();
EFP t = new EFP ();
u2.isqu (u); //u^2
if ((k & 1) == 0) { //sin
//s.sete (u); //(-1)^k*x^(2*k+1)/(2*k+1)!
s.flg = u.flg;
s.epp = u.epp;
s.dvl = u.dvl;
s.cvl = u.cvl;
//t.set0 ();
t.flg = P | Z;
//this.sete (s);
this.flg = s.flg;
this.epp = s.epp;
this.dvl = s.dvl;
this.cvl = s.cvl;
for (int twok1 = 3; this.ne (t); twok1 += 2) { //2*k+1
s.imul (u2).divi ((1 - twok1) * twok1); //(-1)^k*x^(2*k+1)/(2*k+1)!
//t.sete (this);
t.flg = this.flg;
t.epp = this.epp;
t.dvl = this.dvl;
t.cvl = this.cvl;
this.iadd (s);
}
} else { //cos
//s.set1 (); //(-1)^k*x^(2*k)/(2*k)!
s.flg = P;
s.epp = 0;
s.dvl = MSB;
s.cvl = 0L;
//t.set0 ();
t.flg = P | Z;
//this.sete (s);
this.flg = s.flg;
this.epp = s.epp;
this.dvl = s.dvl;
this.cvl = s.cvl;
for (int twok = 2; this.ne (t); twok += 2) { //2*k
s.imul (u2).divi ((1 - twok) * twok); //(-1)^k*x^(2*k)/(2*k)!
//t.sete (this);
t.flg = this.flg;
t.epp = this.epp;
t.dvl = this.dvl;
t.cvl = this.cvl;
this.iadd (s);
}
}
} else { //チェビシェフ展開
if ((k & 1) == 0) { //sin
u2.isqu (u); //u^2
this.imul (SIN_C21, u2)
.iadd (SIN_C19).imul (u2)
.iadd (SIN_C17).imul (u2)
.iadd (SIN_C15).imul (u2)
.iadd (SIN_C13).imul (u2)
.iadd (SIN_C11).imul (u2)
.iadd (SIN_C9).imul (u2)
.iadd (SIN_C7).imul (u2)
.iadd (SIN_C5).imul (u2)
.iadd (SIN_C3).imul (u2)
.iadd (SIN_C1).imul (u);
} else { //cos
u2.isqu (u); //u^2
this.imul (COS_C20, u2)
.iadd (COS_C18).imul (u2)
.iadd (COS_C16).imul (u2)
.iadd (COS_C14).imul (u2)
.iadd (COS_C12).imul (u2)
.iadd (COS_C10).imul (u2)
.iadd (COS_C8).imul (u2)
.iadd (COS_C6).imul (u2)
.iadd (COS_C4).imul (u2)
.iadd (COS_C2).imul (u2)
.iadd (COS_C0);
}
}
this.outer ().neg (k << 30 < 0);
// n*pi/2はn==0を除いて正確に表現できないので、
// RZまたはRPでsin(x)およびcos(x)が-1になることはあり得ない
// RZまたはRMでsin(x)およびcos(x)がcos(0)以外で+1になることはあり得ない
if (this.flg << 1 == 0 && this.epp == 0) { //結果が±1
if (this.flg < 0) { //結果が-1
if (epbRoundingMode == EPB_MODE_RZ || epbRoundingMode == EPB_MODE_RP) { //RZまたはRPで結果が-1
this.sete (NEXTUP_MINUSONE[epbRoundingPrec]);
}
} else { //結果が+1
if (epbRoundingMode == EPB_MODE_RZ || epbRoundingMode == EPB_MODE_RM) { //RZまたはRMで結果が+1
this.sete (NEXTDOWN_PLUSONE[epbRoundingPrec]);
}
}
}
return this.originUpperLower (x).correctUnderflow (savedFpsr);
} //efp.sin(EFP)
//------------------------------------------------------------------------
//x = x.sinh ()
// x=sinh(x)
//y = y.sinh (x)
// y=sinh(x)
// 双曲線正弦 hyperbolic sine ハイパボリックサイン
//
// グラフ
// perl -e "use Math::Trig;use Graph;$g=new Graph();$g->grid();$g->func(sub{sinh($_[0])});print$g"
// echo read("../misc/efp.gp");graph(sinh) | gp -q
// +---------+---------+---------+---------+---------+---------+*--------+---------+
// | | ** |
// | | * |
// | | ** |
// | | ** |
// + + * +
// | | ** |
// | | ** |
// | | * |
// | | ** |
// + + ** +
// | | ** |
// | | ** |
// | | ** |
// | | ** |
// + + *** +
// | | ** |
// | | *** |
// | | *** |
// | |*** |
// +---------+---------+---------+--------***--------+---------+---------+---------+
// | ***| |
// | *** | |
// | *** | |
// | ** | |
// + *** + +
// | ** | |
// | ** | |
// | ** | |
// | ** | |
// + ** + +
// | ** | |
// | * | |
// | ** | |
// | ** | |
// + * + +
// | ** | |
// | ** | |
// | * | |
// | ** | |
// +---------+--------*+---------+---------+---------+---------+---------+---------+
//
// 定義域
// -inf<=x<=inf
//
// 値域
// -inf<=sinh(x)<=inf
//
// 指数関数との関係
// sinh(x)=(e^x-e^-x)/2
// =((e^x)^2-1)/(2*e^x)
//
// テイラー展開
// sinh(x)=x+x^3/3!+x^5/5!+x^7/7!+...
// f(n,x)=sum(k=0,n,x^(2*k+1)/(2*k+1)!)
// echo read("../misc/efp.gp");eval("f(n,x)=sum(k=0,n,1/(2*k+1)!*x^(2*k+1))");a=-0.0625;b=0.0625;for(n=0,12,printf("%4d",floor(closeness(sinh,f(n,x),a,b,10000)))) | gp -q
// 1 3 5 7 9 11 13 15 17 19 21 23 25
// 10 22 36 50 65 80 96 112 128 145 162 179 197
//
// チェビシェフ展開
// 0の近くだけチェビシェフ展開を使う
// echo read("../misc/efp.gp");eval("f(x)=sinh(x)");a=-0.0625;b=0.0625;forstep(n=1,25,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// 1 3 5 7 9 11 13 15 17 19 21 23 25
// 10 24 39 55 71 88 106 124 142 161 179 199 218
// echo read("../misc/efp.gp");eval("f(x)=sinh(x)");a=-0.125;b=0.125;forstep(n=1,25,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// 1 3 5 7 9 11 13 15 17 19 21 23 25
// 8 20 33 47 61 76 92 108 124 141 157 175 192
//
public final EFP sinh () {
return this.sinh (this);
} //efp.sinh()
public final EFP sinh (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
epbFpsr |= EPB_FPSR_X2; //不正確な結果。オーバーフローまたはアンダーフローのときもセットされる
epbExceptionOperandExponent = xf | 0x3fff + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
if (15 <= x.epp) { //x<=-32768||32768<=x。sinh(-big)=-Inf,sinh(+big)=+Inf
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | xf >>> 31]).finish (); //±Inf
}
if (x.epp < -3) { //|x|<0.125
int savedFpsr = epbFpsr;
this.inner ();
if (this == x) {
x = new EFP (x);
}
EFP x2 = new EFP ().isqu (x); //x^2
this.imul (SINH_C13, x2)
.iadd (SINH_C11).imul (x2)
.iadd (SINH_C9).imul (x2)
.iadd (SINH_C7).imul (x2)
.iadd (SINH_C5).imul (x2)
.iadd (SINH_C3).imul (x2)
.iadd (SINH_C1).outer ().mul (x);
return this.originLowerUpper (x).correctUnderflow (savedFpsr);
}
//0.125<=|x|
// xが絶対値の大きい負数のときそのままe^xを計算するとアンダーフローして0になりさらに1/e^xがゼロ除算になる
// オーバーフローだけセットさせるためにxの符号を取ってからe^xを計算する
// 丸める前に符号を付けないとRMとRPが逆になってしまうことに注意する
this.inner ().abs (x).exp (); //e^|x|
this.sub (new EFP ().rcp (this)).div2 ().outer ().neg (xf < 0); //(e^|x|-e^-|x|)/2
if (this.flg << 2 < 0) {
epbFpsr |= EPB_FPSR_OF; //オーバーフロー
return this.sete (OVFL_RESULTS[epbRoundingPrec << 3 | epbRoundingMode << 1 | this.flg >>> 31]).finish (); //±Inf
}
return this;
} //efp.sinh(EFP)
//------------------------------------------------------------------------
//x = x.sqrt ()
// x=sqrt(x)
//y = y.sqrt (x)
// y=sqrt(x)
// 1/2乗(平方根)
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{sqrt($_[0])});print$g"
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + *****
// | | ******** |
// | | ******* |
// | | ******* |
// | | ****** |
// + + ***** +
// | | **** |
// | | *** |
// | |*** |
// | ** |
// +---------+---------+---------+---------*---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
// echo read("../misc/efp.gp");graph(sqrt) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + *****
// | | ******** |
// | | ******* |
// | | ****** |
// | | ****** |
// + + ***** +
// | | **** |
// | | *** |
// | |** |
// | ** |
// +---------+---------+---------+---------*---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
// 変数変換
// EFPの指数部はdoubleに収まらない
// x=x'*2^(2*k) 2^0<=x'<2^2
// sqrt(x)=sqrt(x'*2^(2*k))
// =sqrt(x')*2^k
//
// ニュートン法1
// Math.sqrt()を使ってt=sqrt(x)をdoubleの精度で求めてからニュートン法の反復を1回行う
// f(t)=t^2-x
// f'(t)=2*t
// t'=t-f(t)/f'(t)
// =t-(t^2-x)/(2*t)
// =(2*t^2-(t^2-x))/(2*t)
// =(t^2+x)/(2*t)
// =(t+x/t)/2
// 除算が必要
//
// ニュートン法2
// Math.sqrt()を使ってt=1/sqrt(x)をdoubleの精度で求めてからニュートン法の反復を1回行ってxを掛ける
// f(t)=1/t^2-x
// f'(t)=-2/t^3
// t1=t-f(t)/f'(t)
// =t-(1/t^2-x)/(-2/t^3)
// =t+t/2-x*t^3/2
// =(3*t-x*t^3)/2
// sqrt(x)=x*t1
// =x*(3*t-x*t^3)/2
// 除算は不要
//
// 整数の平方根
// floor(sqrt(x))
// 範囲
// xがs>0桁のときfloor(sqrt(x))はs+1>>1桁
// 1<<(s-1>>1) <= floor(sqrt(x)) <= (s&1)!=0?x>>(s>>1):(1<<(s>>1))-1
// ニュートン法
// 初期値
// t=(s&1)!=0?x>>(s>>1):(1<<(s>>1))-1
// 反復
// t=floor(x/t)+t>>1
// tが減らなくなるまで繰り返す。最後から2番目のtがfloor(sqrt(x))
//
// Math.sqrt(-0.0)はNaNにならず-0.0が返るのでこれに合わせる
//
// テイラー展開
// x=2^(2*n)の近くはsqrt(1+x)-1のテイラー展開を使う
// coeff(sub(a=0,for n:=0:7 sum sub(x=a,df(sqrt(1+x)-1,x,n))/factorial(n)*(x-a)^n),x);
// 1 - 1 1 - 5 7 - 21 33
// {0,---,------,----,------,-----,-------,------}
// 2 8 16 128 256 1024 2048
// for n:=0:7 collect (if n=0 then 0 else (-1)^(n-1)/2^(2*n-1)*factorial(2*n-2)/factorial(n-1)/factorial(n));
// 1 - 1 1 - 5 7 - 21 33
// {0,---,------,----,------,-----,-------,------}
// 2 8 16 128 256 1024 2048
//
public final EFP sqrt () {
return this.sqrt (this);
} //efp.sqrt()
public final EFP sqrt (EFP x) {
int xf = x.flg;
if (xf != 0) { //-x,±0,±Inf,NaN
if (xf == M || xf == (M | I)) { //sqrt(-x)=NaN, sqrt(-Inf)=NaN
epbFpsr |= EPB_FPSR_OE;
if (xf << 2 < 0) { //-Inf
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
} else { //-x
epbExceptionOperandExponent = xf & M | 0x3fff + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
}
this.flg = N;
} else {
this.flg = xf; //sqrt(±0)=±0, sqrt(+Inf)=+Inf, sqrt(NaN)=NaN
}
return this;
}
//+x
if (false) { //ニュートン法。[92] 535ns
this.inner ();
EFP t = new EFP (ONE).max (x);
EFP u = new EFP (x); //thisが破壊されるのでxをコピーしておく
EFP w = new EFP ();
do {
//this.sete (t);
this.flg = t.flg;
this.epp = t.epp;
this.dvl = t.dvl;
this.cvl = t.cvl;
t.iadd (w.sete (u).div (t)).idiv2 (); //t=(t+x/t)/2
} while (this.gt (t));
return this.outer ().finish ();
} else { //Math.sqrtを使う。[92] 70.5ns
if (this == x) {
x = new EFP (x);
}
int xe = x.epp;
if ((xe & 1) != 0 ? (x.dvl >>> -8) == 0xFF : (x.dvl >>> -9) == 0x100) { //仮数部が1-1/256..1+1/256のとき
// 1-1/256=2^-1*0xFF/2^7
// 1+1/256=2^0*0x101/2^8
this.inner ();
x.epp = -(xe & 1); //指数部を-1または0にする
x.dec (); //1を引く
this.imul (x, SQRT1PM1_C11).
iadd (SQRT1PM1_C10).imul (x).
iadd (SQRT1PM1_C9).imul (x).
iadd (SQRT1PM1_C8).imul (x).
iadd (SQRT1PM1_C7).imul (x).
iadd (SQRT1PM1_C6).imul (x).
iadd (SQRT1PM1_C5).imul (x).
iadd (SQRT1PM1_C4).imul (x).
iadd (SQRT1PM1_C3).imul (x).
iadd (SQRT1PM1_C2).imul (x).
iadd (SQRT1PM1_C1).imul (x); //テイラー展開
this.outer ().inc (); //1を加えながら丸める
if (this.flg << 1 == 0) {
//指数部を補正する
// 分かりやすいように10進数で書く
// xの範囲 xの指数 sqrt(x)の範囲 sqrt(x)の指数 dec前とinc後の指数 補正値
// 0.0099<=x<0.0100 -3 0.099<=x<0.1 -2 -1 -1
// 0.0100<=x<0.0101 -2 0.100<=x<0.101 -1 0 -1
// 0.099<=x<0.100 -2
// 0.100<=x<0.101 -1
// 0.99<=x<1 -1 0.99<=x<1 -1 -1 0
// 1<=x<1.01 0 1<=x<1.01 0 0 0
// 9.9<=x<10 0
// 10<=x<10.1 1
// 99<=x<100 1 9.9<=x<10 0 -1 1
// 100<=x<101 2 10<=x<10.1 1 0 1
// 990<=x<1000 2
// 1000<=x<1010 3
// 9900<=x<10000 3 99<=x<100 1 -1 2
// 10000<=x<10100 4 100<=x<101 2 0 2
this.epp += xe + 1 >> 1; //指数部を復元する。負数の右シフトの挙動に注意。ここで指数部が範囲外になることがある
this.finish ();
}
return this;
}
// EFPをdoubleに変換する
// EFPの指数部はdoubleの指数部に収まらないので下位1bitだけ使う
// 仮数部は上位53bitを使う
// Math.sqrtで53bitの平方根を求める
// doubleをEFPに変換する
// 指数部に元の指数部の下位1bitを除いた残りの1/2を加える
// ニュートン法の反復を1回行う
// sqrtでは指数部が正でも負でも半分になるので丸めで制限されるまでオーバーフローもアンダーフローも発生しない
// 丸める
// 結果を2乗する
// 結果の2乗を正確に表現できない場合と結果の2乗と元の値が一致しない場合はX2をセットする
long s = Double.doubleToLongBits (Math.sqrt (Double.longBitsToDouble ((long) (1023 + (xe & 1)) << 52 | x.dvl << 1 >>> 12)));
EFP t = new EFP (P, (int) (s >>> 52) - 1023 + (xe >> 1), MSB | s << 12 >>> 1, 0L);
int savedFpsr = epbFpsr;
this.inner ().div (x, t).iadd (t).outer ();
this.epp--; //(t+x/t)/2
epbFpsr = 0;
this.finish ();
savedFpsr |= epbFpsr & (EPB_FPSR_OF | EPB_FPSR_UF);
this.inner ();
t.squ (this);
this.outer ();
if ((epbFpsr & EPB_FPSR_X2) != 0 || !t.eq (x)) {
savedFpsr |= EPB_FPSR_X2; //不正確な結果
epbExceptionOperandExponent = xf | 0x3fff + x.epp << 16;
epbExceptionOperandMantissa = x.dvl;
}
epbFpsr = savedFpsr;
return this;
}
} //efp.sqrt(EFP)
//------------------------------------------------------------------------
//x = x.squ ()
// x*=x
//y = y.squ (x)
// y=x^2
// 2乗
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{$_[0]**2});print$g"
// echo read("../misc/efp.gp");eval("squ(x)=x^2");graph(squ) | gp -q
// +---------+---------*---------+---------+---------+---------*---------+---------+
// | ** | ** |
// | * | * |
// | ** | ** |
// | * | * |
// + ** + ** +
// | ** | ** |
// | * | * |
// | ** | ** |
// | ** | ** |
// + * + * +
// | ** | ** |
// | ** | ** |
// | ** | ** |
// | ** | ** |
// + ** + ** +
// | ** | ** |
// | ** | ** |
// | *** | *** |
// | *** | *** |
// +---------+---------+---------+------*******------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
public final EFP squ () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf << 3 < 0 ? N : xf & ~M; //(±0)^2=+0, (±Inf)^2=+Inf, NaN^2=NaN
return this;
}
//3分割する
// 92bitの仮数部を32bit,30bit,30bitに分割する
long zd = this.dvl;
long zc = this.cvl;
long zb = (zd << -2 | zc >>> 2) >>> -30; //下位30bit
zc = zd << 32 >>> -30; //中位30bit
zd >>>= 32; //上位32bit
//2乗する
// (zd*2^60+zc*2^30+zb)^2=zd^2*2^120+2*zd*zc*2^90+(2*zd*zb+zc^2)*2^60+2*zc*zb*2^30+zb^2
long t = zb * zb; //2^0
long s = t & 0xffffffffL; //sticky bit
t = (t >>> 30) + (zc * zb << 1); //2^30
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zb << 1) + zc * zc; //2^60
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zc << 1); //2^90
zd = (t >>> 30) + zd * zd; //2^120
zc = t << -30 | s;
int ze = this.epp << 1;
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.finish (P, ze, zd, zc, 0L);
} //efp.squ()
public final EFP isqu () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf << 3 < 0 ? N : xf & ~M; //(±0)^2=+0, (±Inf)^2=+Inf, NaN^2=NaN
return this;
}
//3分割する
// 92bitの仮数部を32bit,30bit,30bitに分割する
long zd = this.dvl;
long zc = this.cvl;
long zb = (zd << -2 | zc >>> 2) >>> -30; //下位30bit
zc = zd << 32 >>> -30; //中位30bit
zd >>>= 32; //上位32bit
//2乗する
// (zd*2^60+zc*2^30+zb)^2=zd^2*2^120+2*zd*zc*2^90+(2*zd*zb+zc^2)*2^60+2*zc*zb*2^30+zb^2
long t = zb * zb; //2^0
long s = t & 0xffffffffL; //sticky bit
t = (t >>> 30) + (zc * zb << 1); //2^30
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zb << 1) + zc * zc; //2^60
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zc << 1); //2^90
zd = (t >>> 30) + zd * zd; //2^120
zc = t << -30 | s;
int ze = this.epp << 1;
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.ifinish (P, ze, zd, zc, 0L);
} //efp.isqu()
public final EFP squ (EFP x) {
//return this.mul (x, x); //11.8ns
//8.4ns
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf << 3 < 0 ? N : xf & ~M; //(±0)^2=+0, (±Inf)^2=+Inf, NaN^2=NaN
return this;
}
//3分割する
// 92bitの仮数部を32bit,30bit,30bitに分割する
long zd = x.dvl;
long zc = x.cvl;
long zb = (zd << -2 | zc >>> 2) >>> -30; //下位30bit
zc = zd << 32 >>> -30; //中位30bit
zd >>>= 32; //上位32bit
//2乗する
// (zd*2^60+zc*2^30+zb)^2=zd^2*2^120+2*zd*zc*2^90+(2*zd*zb+zc^2)*2^60+2*zc*zb*2^30+zb^2
long t = zb * zb; //2^0
long s = t & 0xffffffffL; //sticky bit
t = (t >>> 30) + (zc * zb << 1); //2^30
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zb << 1) + zc * zc; //2^60
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zc << 1); //2^90
zd = (t >>> 30) + zd * zd; //2^120
zc = t << -30 | s;
int ze = x.epp << 1;
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.finish (P, ze, zd, zc, 0L);
} //efp.squ(EFP)
public final EFP isqu (EFP x) {
//return this.mul (x, x); //11.8ns
//8.4ns
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf << 3 < 0 ? N : xf & ~M; //(±0)^2=+0, (±Inf)^2=+Inf, NaN^2=NaN
return this;
}
//3分割する
// 92bitの仮数部を32bit,30bit,30bitに分割する
long zd = x.dvl;
long zc = x.cvl;
long zb = (zd << -2 | zc >>> 2) >>> -30; //下位30bit
zc = zd << 32 >>> -30; //中位30bit
zd >>>= 32; //上位32bit
//2乗する
// (zd*2^60+zc*2^30+zb)^2=zd^2*2^120+2*zd*zc*2^90+(2*zd*zb+zc^2)*2^60+2*zc*zb*2^30+zb^2
long t = zb * zb; //2^0
long s = t & 0xffffffffL; //sticky bit
t = (t >>> 30) + (zc * zb << 1); //2^30
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zb << 1) + zc * zc; //2^60
s |= t & 0xffffffffL;
t = (t >>> 30) + (zd * zc << 1); //2^90
zd = (t >>> 30) + zd * zd; //2^120
zc = t << -30 | s;
int ze = x.epp << 1;
if (zd < 0L) {
ze++;
} else {
zd = zd << 1 | zc >>> -1;
zc <<= 1;
}
return this.ifinish (P, ze, zd, zc, 0L);
} //efp.isqu(EFP)
//------------------------------------------------------------------------
//x = x.sub (y)
// x-=y
//z = z.sub (x, y)
// z=x-y
// 減算
//
// (xn/xd)-(yn/yd)
// =((xn*yd)/(xd*yd))-((xd*yn)/(xd*yd))
// =(xn*yd-xd*yn)/(xd*yd)
//
public final EFP sub (EFP y) {
int xf = this.flg;
int xe = this.epp;
long xd = this.dvl;
long xc = this.cvl;
long xb = 0L;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf | yf) << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
return this;
}
if ((xf & yf) << 2 < 0 && xf == yf) { //両方±Infで符号が同じときNaN
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N;
return this;
}
if ((xf & yf) << 1 < 0 && xf == yf) { //両方±0で符号が同じとき
this.flg = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
return this;
}
if (xf << 1 < 0 || yf << 2 < 0) { //xが±0またはyが±Infのとき-y
xf = yf ^ M;
xe = y.epp;
xd = y.dvl;
xc = y.cvl;
}
//xが±Infまたはyが±0のときx
} else { //両方±0,±Inf,NaN以外
//減算なのでyの符号を反転して加算する
yf ^= M;
long yd = y.dvl;
long yc = y.cvl;
int o = xe - y.epp;
if (o < 0 || o == 0 && (xd < yd || xd == yd && xc >>> 1 < yc >>> 1)) { //yの方が絶対値が大きい
//xとyを入れ換える
xf = yf;
xe += o = -o; //xe=y.epp
xd = yd;
xc = yc;
yf = this.flg; //後で符号を比較するときに使う
yd = this.dvl;
yc = this.cvl;
}
//xの方が絶対値が大きいか等しい
//yを右にずらして小数点の位置を合わせる
if (0 < o) {
if (o <= 63) {
xb = yc << -o;
yc = yd << -o | yc >>> o;
yd >>>= o;
} else if (o == 64) {
xb = yc;
yc = yd;
yd = 0L;
} else if (o <= 127) {
xb = yd << -o | yc;
yc = yd >>> o;
yd = 0L;
} else {
xb = yd | yc; //絶対値減算を行うとき下位からのボローとして必要
yc = 0L;
yd = 0L;
}
}
//絶対値加算または絶対値減算を行う
if (xf == yf) { //符号が同じなので絶対値加算を行う
//yc[1]とyc[0]をsticky bitに押し出す
xb |= yc << 62;
//右にずらしてxd[63]を空ける
xc = xd << 63 | xc >>> 1;
xd >>>= 1;
yc = yd << 63 | yc >>> 1;
yd >>>= 1;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//足す
xc += yc;
xd += yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//溢れの処理
if (xd < 0L) { //溢れたとき
xe++;
} else { //溢れなかったとき
xd = xd << 1 | xc >>> 63; //左にずらしてxd[63]を詰める
xc <<= 1;
}
} else { //符号が異なるので絶対値減算を行う
//yc[0]をsticky bitに押し出す
xb |= yc << 63;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//引く
// xの方が絶対値が大きいか等しいので負になることはないが0になることがある
if (xb != 0L) {
xc--;
}
xc -= yc;
xd -= yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//正規化する
if (0L <= xd) {
if (xd != 0L) {
xe -= o = Long.numberOfLeadingZeros (xd);
xd = xd << o | xc >>> -o;
xc <<= o;
} else if (xc != 0L) {
xe -= o = 64 + Long.numberOfLeadingZeros (xc);
xd = xc << o;
xc = 0L;
} else { //0になった
xf = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
}
}
} //if 符号が同じなので絶対値加算を行う/符号が異なるので絶対値減算を行う
} //if どちらかが±0,±Inf,NaN/両方±0,±Inf,NaN以外
return this.finish (xf, xe, xd, xc, xb);
} //efp.sub(EFP)
public final EFP sub (EFP x, EFP y) {
int xf = x.flg;
int xe = x.epp;
long xd = x.dvl;
long xc = x.cvl;
long xb = 0L;
int yf = y.flg;
if ((xf | yf) << 1 != 0) { //どちらかが±0,±Inf,NaN
if ((xf | yf) << 3 < 0) { //どちらかがNaNのときNaN
this.flg = N;
return this;
}
if ((xf & yf) << 2 < 0 && xf == yf) { //両方±Infで符号が同じときNaN
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = yf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N;
return this;
}
if ((xf & yf) << 1 < 0 && xf == yf) { //両方±0で符号が同じとき
this.flg = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
return this;
}
if (xf << 1 < 0 || yf << 2 < 0) { //xが±0またはyが±Infのとき-y
xf = yf ^ M;
xe = y.epp;
xd = y.dvl;
xc = y.cvl;
}
//xが±Infまたはyが±0のときx
} else { //両方±0,±Inf,NaN以外
//減算なのでyの符号を反転して加算する
yf ^= M;
long yd = y.dvl;
long yc = y.cvl;
int o = xe - y.epp;
if (o < 0 || o == 0 && (xd < yd || xd == yd && xc >>> 1 < yc >>> 1)) { //yの方が絶対値が大きい
//xとyを入れ換える
xf = yf;
xe += o = -o; //xe=y.epp
xd = yd;
xc = yc;
yf = x.flg; //後で符号を比較するときに使う
yd = x.dvl;
yc = x.cvl;
}
//xの方が絶対値が大きいか等しい
//yを右にずらして小数点の位置を合わせる
if (0 < o) {
if (o <= 63) {
xb = yc << -o;
yc = yd << -o | yc >>> o;
yd >>>= o;
} else if (o == 64) {
xb = yc;
yc = yd;
yd = 0L;
} else if (o <= 127) {
xb = yd << -o | yc;
yc = yd >>> o;
yd = 0L;
} else {
xb = yd | yc; //絶対値減算を行うとき下位からのボローとして必要
yc = 0L;
yd = 0L;
}
}
//絶対値加算または絶対値減算を行う
if (xf == yf) { //符号が同じなので絶対値加算を行う
//yc[1]とyc[0]をsticky bitに押し出す
xb |= yc << 62;
//右にずらしてxd[63]を空ける
xc = xd << 63 | xc >>> 1;
xd >>>= 1;
yc = yd << 63 | yc >>> 1;
yd >>>= 1;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//足す
xc += yc;
xd += yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//溢れの処理
if (xd < 0L) { //溢れたとき
xe++;
} else { //溢れなかったとき
xd = xd << 1 | xc >>> 63; //左にずらしてxd[63]を詰める
xc <<= 1;
}
} else { //符号が異なるので絶対値減算を行う
//yc[0]をsticky bitに押し出す
xb |= yc << 63;
//下位を右にずらしてxc[63]を空ける
yc >>>= 1;
xc >>>= 1;
//引く
// xの方が絶対値が大きいか等しいので負になることはないが0になることがある
if (xb != 0L) {
xc--;
}
xc -= yc;
xd -= yd + (xc >>> 63);
//下位を左にずらしてxc[63]を詰める
xc <<= 1;
//正規化する
if (0L <= xd) {
if (xd != 0L) {
xe -= o = Long.numberOfLeadingZeros (xd);
xd = xd << o | xc >>> -o;
xc <<= o;
} else if (xc != 0L) {
xe -= o = 64 + Long.numberOfLeadingZeros (xc);
xd = xc << o;
xc = 0L;
} else { //0になった
xf = epbRoundingMode == EPB_MODE_RM ? M | Z : P | Z; //RMのとき-0,それ以外は+0
}
}
} //if 符号が同じなので絶対値加算を行う/符号が異なるので絶対値減算を行う
} //if どちらかが±0,±Inf,NaN/両方±0,±Inf,NaN以外
return this.finish (xf, xe, xd, xc, xb);
} //efp.sub(EFP,EFP)
//------------------------------------------------------------------------
//x = x.tan ()
// x=tan(x)
//y = y.tan (x)
// y=tan(x)
// 正接 tangent タンジェント
//
// グラフ
// perl -e "use Math::Trig;use Graph;$g=new Graph();$g->grid();$g->func(sub{tan($_[0])});print$g"
// echo read("../misc/efp.gp");graph(tan) | gp -q
// +---------+---------+-*-------+---------+---------+--*------+---------+---------+
// | * | * |
// | * | * |
// | ** | * |
// | * | * |
// + * + ** +
// | * | * |
// | ** | * |
// | * | * |
// | * | ** |
// + ** + * +
// | * | ** |
// | ** | * |
// | * | ** |
// | ** | ** *
// + ** + ** **
// | ** | ** **|
// | *** | ** *** |
// | *** | *** *** |
// | ** |*** *** |
// +-------***---------+---------+--------***--------+---------+---------***-------+
// | *** ***| ** |
// | *** *** | *** |
// | *** ** | *** |
// |** ** | ** |
// ** ** + ** +
// * ** | ** |
// | ** | * |
// | * | ** |
// | ** | * |
// + * + ** +
// | ** | * |
// | * | * |
// | * | ** |
// | * | * |
// + ** + * +
// | * | * |
// | * | ** |
// | * | * |
// | * | * |
// +---------+---------+------*--+---------+---------+-------*-+---------+---------+
//
// 定義域
// -inf<=x<=inf
//
// 値域
// -inf<=tan(x)<=inf
//
// 三角関数のとの関係
// tan(x)=sin(x)/cos(x)
//
// 加法定理
// tan(x+y)=(tan(x)+tan(y))/(1-tan(x)*tan(y))
//
// 倍角と半角
// tan(2*x)=tan(x+x)
// =(tan(x)+tan(x))/(1-tan(x)*tan(x))
// =2*tan(x)/(1-tan(x)^2)
// tan(3*x)=tan(2*x+x)
// =(tan(2*x)+tan(x))/(1-tan(2*x)*tan(x))
// =(2*tan(x)/(1-tan(x)^2)+tan(x))/(1-2*tan(x)/(1-tan(x)^2)*tan(x))
// =(tan(x)^3-3*tan(x))/(3*tan(x)^2-1)
// tan(x)=2*tan(x/2)/(1-tan(x/2)^2)
// tan(x/2)=(+/-sqrt(tan(x)^2+1)-1)/tan(x)
//
// 変数変換1
// 収束を速くするために|x|<=pi/8にする
// tan(pi/4)=1
// tan(x+pi/4)=(tan(x)+tan(pi/4))/(1-tan(x)*tan(pi/4))
// =(tan(x)+1)/(1-tan(x))
// tan(3*pi/4)=-1
// tan(x+3*pi/4)=(tan(x)+tan(3*pi/4))/(1-tan(x)*tan(3*pi/4))
// =(tan(x)-1)/(1+tan(x))
// tan(x)=(tan(x-pi/4)+1)/(1-tan(x-pi/4))
// =-1/tan(x-pi/2)
// =(tan(x-3*pi/4)-1)/(1+tan(x-3*pi/4))
// =tan(x-pi)
// -1/tan(x-pi/2)
// k=3 k=2
// ← ←
// \ │ / (tan(x-pi/4)+1)/(1-tan(x-pi/4))
// \ \ │ / /
// \ \│/ / ↑k=1
// k=0↓~~-- \│/ --~~
// tan(x-pi) ────・──── tan(x)
// __-- /│\ --__↑k=0
// k=1↓ / /│\ \
// / / │ \ \
// / │ \
// → →
// k=2 k=3
//
// 変数変換2
// 場合分けを増やせばチェビシェフ展開の多項式を短くすることができる
// tan(pi/8)=(sqrt(tan(pi/4)^2+1)-1)/tan(pi/4)
// =(sqrt(1^2+1)-1)/1
// =sqrt(2)-1
// tan(3*pi/8)=(tan(pi/8)^3-3*tan(pi/8))/(3*tan(pi/8)^2-1)
// =((sqrt(2)-1)^3-3*(sqrt(2)-1))/(3*(sqrt(2)-1)^2-1)
// =(2-sqrt(2))/(3*sqrt(2)-4)
// =(2-sqrt(2))*(3*sqrt(2)+4)/(3*sqrt(2)-4)/(3*sqrt(2)+4)
// =(8-6+(6-4)*sqrt(2))/2
// =sqrt(2)+1
// tan(x)=(tan(x-pi/8)+sqrt(2)-1)/(1-tan(x-pi/8)*(sqrt(2)-1))
// =(tan(x-3*pi/8)+sqrt(2)+1)/(1-tan(x-3*pi/8)*(sqrt(2)+1))
// =(tan(x-5*pi/8)-(sqrt(2)+1))/(1+tan(x-3*pi/8)*(sqrt(2)+1))
// =(tan(x-7*pi/8)-(sqrt(2)-1))/(1+tan(x-3*pi/8)*(sqrt(2)-1))
//
// ローラン級数展開
// tan(x)=x-x^3/3+2*x^5/15-17*x^7/315+...
// =sum[n=1..inf]{(-1)^n*4^n*(1-4^n)*B(2*n)*x^(2*n-1)/(2*n)!} |x|<pi/2
// f(n,x)=sum(k=1,n,(-1)^k*4^k*(1-4^k)*bernreal(2*k)*x^(2*k-1)/(2*k)!)
//
// チェビシェフ展開
// echo read("../misc/efp.gp");eval("f(x)=tan(x)");a=-Pi/8;b=Pi/8;forstep(n=1,35,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=tan(x)");a=-Pi/16;b=Pi/16;forstep(n=1,35,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=tan(x)");a=-Pi/32;b=Pi/32;forstep(n=1,35,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=tan(x)");a=-Pi/64;b=Pi/64;forstep(n=1,21,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=tan(x)");a=-Pi/128;b=Pi/128;forstep(n=1,21,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=tan(x)");a=-Pi/256;b=Pi/256;forstep(n=1,15,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35
// 4 9 15 20 26 32 38 43 49 55 61 67 72 78 84 90 96 102 |x|<=pi/8
// 6 13 21 29 36 44 52 60 67 75 83 91 99 107 115 123 130 138 |x|<=pi/16 pi/8 4要素
// 8 17 27 37 46 56 66 76 86 95 105 115 125 135 145 155 165 175 |x|<=pi/32 pi/16 8要素
// 10 21 33 45 56 68 80 92 104 115 127 |x|<=pi/64 pi/32 16要素
// 12 25 39 53 66 80 94 108 122 135 149 |x|<=pi/128 pi/64 32要素
// 14 29 45 61 76 92 108 124 |x|<=pi/256 pi/128 64要素
//
public final EFP tan () {
return this.tan (this);
} //efp.tan()
public final EFP tan (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
this.flg = xf; //tan(±0)=±0
} else if (xf << 2 < 0) { //±Inf
epbFpsr |= EPB_FPSR_OE;
epbExceptionOperandExponent = xf & M | 0x7fff << 16;
epbExceptionOperandMantissa = 0x0000000000000000L;
this.flg = N; //tan(±Inf)=NaN
} else { //NaN
this.flg = N; //tan(NaN)=NaN
}
return this;
}
//±0,±Inf,NaN以外
if (false) { //sin/cos。[90] 800ns
EFP c = new EFP ().inner ().cos (x); //cos(x)
return this.sin (x).outer ().div (c); //sin(x)/cos(x)
} else if (false) { //4分割。[90] 600ns
this.inner ();
EFP s = new EFP ();
EFP t = new EFP ();
EFP u = new EFP ().iabs (x); //|x|
EFP u2 = new EFP ();
int k = 0; //|x|+pi/8の8分象限
//if (u.gt (PI_8)) { //|x|>pi/8
if (u.epp >= -1 || (u.epp == -2 && u.dvl >= 0xc90fdaa22168c234L)) { //|x|>=pi/8。下位の比較は省略する
//s.iadd (u, PI_8).quo (PI_4); //|x|+pi/8をpi/4で割った商
s.iadd (u, PI_8).imul (FOUR_PI).trunc (); //|x|+pi/8をpi/4で割った商
// |x|をpi/4で割った余りを求めるとき|x|がpi/4の整数倍に近いと桁落ちが発生するので倍精度で計算する
u.sub (t.imulw (u2, s, PI_4)).sub (u2).sub (t.imul (s, PI_4A)); //|x|をpi/4で割った余り。[-pi/8,pi/8]
k = s.geti () & 3; //|x|+pi/8の8分象限
}
u2.isqu (u); //u^2
this.imul (TAN_C33, u2)
.iadd (TAN_C31).imul (u2)
.iadd (TAN_C29).imul (u2)
.iadd (TAN_C27).imul (u2)
.iadd (TAN_C25).imul (u2)
.iadd (TAN_C23).imul (u2)
.iadd (TAN_C21).imul (u2)
.iadd (TAN_C19).imul (u2)
.iadd (TAN_C17).imul (u2)
.iadd (TAN_C15).imul (u2)
.iadd (TAN_C13).imul (u2)
.iadd (TAN_C11).imul (u2)
.iadd (TAN_C9).imul (u2)
.iadd (TAN_C7).imul (u2)
.iadd (TAN_C5).imul (u2)
.iadd (TAN_C3).imul (u2)
.iadd (TAN_C1).imul (u);
if (k == 1) {
t.negdec (this); //1-tan(x-pi/4)
this.inc ().div (t); //(1+tan(x-pi/4))/(1-tan(x-pi/4))
} else if (k == 2) {
this.rcp ().ineg (); //-1/tan(x-pi/2)
} else if (k == 3) {
t.inc (this); //tan(x-3*pi/4)+1
this.dec ().div (t); //(tan(x-3*pi/4)-1)/(tan(x-3*pi/4)+1)
}
return this.outer ().neg (xf < 0); //tanは奇関数なのでxの符号を掛ける
} else { //128分割。[90] 350ns
if (x.epp >= 16) { //|x|が大きすぎる
EFP c = new EFP ().inner ().cos (x); //cos(x)
return this.sin (x).outer ().div (c); //sin(x)/cos(x)
}
int savedFpsr = epbFpsr;
this.inner ();
if (this == x) {
x = new EFP (x);
}
if (x.epp < -3) { //|x|<1/8
EFP x2 = new EFP ().isqu (x); //x^2
this.imul (TAN8_C21, x2)
.iadd (TAN8_C19).imul (x2)
.iadd (TAN8_C17).imul (x2)
.iadd (TAN8_C15).imul (x2)
.iadd (TAN8_C13).imul (x2)
.iadd (TAN8_C11).imul (x2)
.iadd (TAN8_C9).imul (x2)
.iadd (TAN8_C7).imul (x2)
.iadd (TAN8_C5).imul (x2)
.iadd (TAN8_C3).imul (x2)
.iadd (TAN8_C1).outer ().mul (x);
return this.originLowerUpper (x).correctUnderflow (savedFpsr);
}
EFP s = new EFP ();
EFP t = new EFP ();
EFP u = new EFP ().iabs (x); //|x|
EFP u2 = new EFP ();
s.iadd (u, TAN7_X).imul (TAN7_Y).trunc (); //|x|+pi/256をpi/128で割った商
// |x|をpi/128で割った余りを求めるとき|x|がpi/128の整数倍に近いと桁落ちが発生するので倍精度で計算する
u.sub (t.imulw (u2, s, TAN7_Z)).sub (u2).sub (t.imul (s, TAN7_ZA)); //|x|をpi/128で割った余り。[-pi/256,pi/256]
int k = s.geti () & 127; //|x|+pi/256をpi/128で割った商の下位7bit
u2.isqu (u); //u^2
this.imul (TAN7_C11, u2)
.iadd (TAN7_C9).imul (u2)
.iadd (TAN7_C7).imul (u2)
.iadd (TAN7_C5).imul (u2)
.iadd (TAN7_C3).imul (u2)
.iadd (TAN7_C1).imul (u);
if (k != 0) {
if (k <= 63) {
t = TAN7_T[k];
s.imul (this, t).negdec ();
this.iadd (t).div (s); //(tan(x-k*pi/128)+t)/(1-tan(k*pi/128)*t)
} else if (k == 64) {
this.rcp ().ineg (); //-1/tan(x-pi/2)
} else {
t = TAN7_T[128 - k];
s.imul (this, t).inc ();
this.sub (t).div (s); //(tan(x-(128-k)*pi/128)-t)/(1+tan((128-k)*pi/128)*t)
}
}
return this.outer ().neg (xf < 0); //tanは奇関数なのでxの符号を掛ける
}
} //efp.tan(EFP)
//------------------------------------------------------------------------
//x = x.tanh ()
// x=tanh(x)
//y = y.tanh (x)
// y=tanh(x)
// 双曲線正接 hyperbolic tangent ハイパボリックタンジェント
//
// グラフ
// perl -e "use Math::Trig;use Graph;$g=new Graph();$g->grid();$g->func(sub{tanh($_[0])});print$g"
// echo read("../misc/efp.gp");graph(tanh) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + **************************
// | | ******* |
// | | ***** |
// | | *** |
// | |*** |
// +---------+---------+---------+--------***--------+---------+---------+---------+
// | ***| |
// | *** | |
// | ***** | |
// | ******* | |
// ************************** + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// + + +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
//
// 定義域
// -inf<=x<=inf
//
// 値域
// -1<=tanh(x)<=1
//
// 双曲線関数との関係
// tanh(x)=sinh(x)/cosh(x)
//
// 指数関数との関係
// tanh(x)=(e^x-e^(-x))/(e^x+e^(-x))
// =(e^(2*x)-1)/(e^(2*x)+1)
// 1-tanh(x)=2*e^-x/(e^x+e^-x)
//
// 微分
// df{tanh(x)}=1-tanh(x)^2
// =sech(x)^2
// =1/cosh(x)^2
//
// 加法定理
// tanh(x+y)=(tanh(x)+tanh(y))/(1+tanh(x)*tanh(y))
//
// 定義域の制限
// 仮数部がLENbitのとき|x|<=atanh(1-2^-LEN)でなければtanh(x)とsgn(x)を区別できない
// 92bitならば
// > atanh(1-2^-92);
// 32.231343896037456887901293647754723317576611492206
//
// 変数変換1
// tanh(x+log((c+1)/(c-1))/2)=tanh(x+log((1+1/c)/(1-1/c))/2)
// =tanh(x+atanh(1/c))
// =(tanh(x)+tanh(atanh(1/c)))/(1+tanh(x)*tanh(atanh(1/c)))
// =(tanh(x)+1/c)/(1+tanh(x)*1/c)
// =(c*tanh(x)+1)/(c+tanh(x))
// =(c^2+c*tanh(x)-c^2+1)/(c+tanh(x))
// =c-(c^2-1)/(c+tanh(x))
// tanh(x+1*log((c+1)/(c-1))/2)=(c*tanh(x)+1)/(c+tanh(x))
// tanh(x+2*log((c+1)/(c-1))/2)=(c^2*tanh(x)+2*c+tanh(x))/(c^2+2*c*tanh(x)+1)
// tanh(x+3*log((c+1)/(c-1))/2)=(c^3*tanh(x)+3*c^2+3*c*tanh(x)+1)/(c^3+3*c^2*tanh(x)+3*c+tanh(x))
// tanh(x+4*log((c+1)/(c-1))/2)=(c^4*tanh(x)+4*c^3+6*c^2*tanh(x)+4*c+tanh(x))/(c^4+4*c^3*tanh(x)+6*c^2+4*c*tanh(x)+1)
// tanh(x+5*log((c+1)/(c-1))/2)=(c^5*tanh(x)+5*c^4+10*c^3*tanh(x)+10*c^2+5*c*tanh(x)+1)/(c^5+5*c^4*tanh(x)+10*c^3+10*c^2*tanh(x)+5*c+tanh(x))
// tanh(x+k*log((c+1)/(c-1))/2)は(c+1)^kを二項展開してkと奇偶が同じ項にtanh(x)を掛けたものをkと奇偶が異なる項にtanh(x)を掛けたもので割ったものになっている
// cが定数でkが大きすぎなければすべてのkについてc0+1/(c1+c2*tanh(x))の形に整理して係数をテーブルに列挙しておくことができる
// log((c+1)/(c-1))/2が2の累乗になるようにcを定めれば分割に除算はいらない
// 例えば、|x|<=1/4の範囲をチェビシェフ展開する場合、幅が1/2なので
// log((c+1)/(c-1))/2=1/2
// log((c+1)/(c-1))=1
// (c+1)/(c-1)=e
// c=(e+1)/(e-1)
// を使ってテーブルを作ればよい
// しかし、チェビシェフ展開の項数を減らそうとして幅を狭くするとテーブルが巨大化してしまう
// 実用的な範囲ではtanh(x)=(e^(2*x)-1)/(e^(2*x)+1)より速くならないかも知れない
//
// 変数変換2
// tanh(x+k*log((c+1)/(c-1))/2)でk=2^jの式だけテーブルに展開しておいて平行移動の式を動的に作る
// 分子と分母を分けておけば除算は最後の1回だけで済む
//
// 変数変換3
// xの指数部を見て開始範囲を選択する
// テーブルを参照してxが範囲の中央の1/3に含まれているか確認する
// 中央の1/3に含まれていない場合は中央の1/3まで平行移動するための式を分子と分母に分けて作る
// xが十分に小さくなるまで繰り返す
// チェビシェフ展開で計算する
// 平行移動の式で元の位置に戻す。最後に1回だけ除算が必要になる
//
// ローラン級数展開
// tanh(x)=x+x^3/3+2*x^5/15+17*x^7/315+...
// =sum[n=1..inf]{4^n*(4^n-1)*B(2*n)*x^(2*n-1)/(2*n)!} |x|<pi/2
// f(n,x)=sum(k=1,n,4^k*(4^k-1)*bernreal(2*k)*x^(2*k-1)/(2*k)!)
// echo for(k=1,10,x=eval("4^k*(4^k-1)*bernfrac(2*k)/(2*k)!");print(" // ",x,"*x^",2*k-1)) | gp -q
// 1*x^1
// -1/3*x^3
// 2/15*x^5
// -17/315*x^7
// 62/2835*x^9
// -1382/155925*x^11
// 21844/6081075*x^13
// -929569/638512875*x^15
// 6404582/10854718875*x^17
// -443861162/1856156927625*x^19
//
// チェビシェフ展開
// 0の近くだけチェビシェフ展開を使う
// echo read("../misc/efp.gp");eval("f(x)=tanh(x)");a=-0.25;b=0.25;forstep(n=1,31,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=tanh(x)");a=-0.125;b=0.125;forstep(n=1,31,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// echo read("../misc/efp.gp");eval("f(x)=tanh(x)");a=-0.0625;b=0.0625;forstep(n=1,31,2,printf("%4d",floor(closeness(f,chebyshev(f,a,b,n),a,b,10000)))) | gp -q
// 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31
// 6 12 19 26 33 40 47 54 61 69 76 83 90 97 105 112
// 8 16 25 34 43 52 61 70 79 88 98 107 116 125 134 144
// 10 20 31 42 53 64 75 86 97 108 120 131 142 153 164 176
//
public final EFP tanh () {
return this.tanh (this);
} //efp.tanh()
public final EFP tanh (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 2 < 0) { //tanh(±Inf)=±1
this.flg = xf & M;
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
} else { //tanh(±0)=±0, tanh(NaN)=NaN
this.flg = xf;
}
return this;
}
//±0,±Inf,NaN以外
// e^xを経由する方法はオーバーフローを発生させずに計算できる範囲が狭いので|x|が大きい場合を分ける必要がある
int xe = x.epp;
if (xe < -2) { //|x|<0.25
int savedFpsr = epbFpsr;
this.inner ();
if (this == x) {
x = new EFP (x);
}
EFP x2 = new EFP ().isqu (x); //x^2
this.imul (TANH_C27, x2)
.iadd (TANH_C25).imul (x2)
.iadd (TANH_C23).imul (x2)
.iadd (TANH_C21).imul (x2)
.iadd (TANH_C19).imul (x2)
.iadd (TANH_C17).imul (x2)
.iadd (TANH_C15).imul (x2)
.iadd (TANH_C13).imul (x2)
.iadd (TANH_C11).imul (x2)
.iadd (TANH_C9).imul (x2)
.iadd (TANH_C7).imul (x2)
.iadd (TANH_C5).imul (x2)
.iadd (TANH_C3).imul (x2)
.iadd (TANH_C1).outer ().mul (x);
return this.originUpperLower (x).correctUnderflow (savedFpsr);
}
//0.25<=|x|
if (false) {
EFP c = new EFP ().inner ().cosh (x); //cosh(x)
return this.sinh (x).outer ().div (c); //sinh(x)/cosh(x) [90]
} else if (6 <= xe) { //2^6<=|x|
// x=2^6のとき
// 1-tanh(x)=1-(e^x-e^(-x))/(e^x+e^(-x))
// =2*e^(-x)/(e^x+e^(-x))
// の値は
// echo x=eval("2^6");log(2*exp(-x)/(exp(x)+exp(-x)))/log(2) | gp -q
// -183.66496523378731614207035916824219359
// であるから2^6<=xのときtanh(x)と1を区別できない
// tanh(x)は奇関数なのでx<=-2^6の場合も同様にtanh(x)と-1を区別できない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
this.flg = xf & M; //±1
this.epp = 0;
this.dvl = MSB;
this.cvl = 0L;
if (xf < 0) {
if (epbRoundingMode == EPB_MODE_RZ || epbRoundingMode == EPB_MODE_RP) {
this.nextup (epbRoundingPrec);
}
} else {
if (epbRoundingMode == EPB_MODE_RZ || epbRoundingMode == EPB_MODE_RM) {
this.nextdown (epbRoundingPrec);
}
}
return this;
} else {
EFP t = new EFP ().inner ().imul2 (x).exp (); //e^(2*x)
this.dec (t);
t.inc ();
return this.outer ().div (t); //(e^(2*x)-1)/(e^(2*x)+1) [90]
}
} //efp.tanh(EFP)
//------------------------------------------------------------------------
//x = x.tgamma ()
// x=Γ(x)
//y = y.tgamma (x)
// y=Γ(x)
// ガンマ関数
//
// グラフ
// echo read("../misc/efp.gp");graph(gamma) | gp -q
// *---------*---------+**----**-+---------+-*-------+---------+---------+-----**--+
// * * * * | * * |
// * * * * | ** ** |
// * * * * | * * |
// * ** * * | * ** |
// * * * ** + * * +
// * * ** * | * ** |
// * * * * | ** ** |
// * * **** | * ** |
// * * | * * |
// * * + ** *** +
// * * | * ** |
// * * | ** ** |
// * * | ** *** |
// * * | *** **** |
// ** ** + ***** ******* +
// |* * | **** |
// |* ** | |
// |** ** | |
// | ***** | |
// +---------+---------+---------+---------+---------+---------+---------+---------+
// | | |
// | | |
// | | |
// | ** | |
// + ***** + +
// | * ** | |
// | ** * | |
// | * * | |
// | * ** | |
// + * * + +
// | * * | |
// | * * | |
// | * * | |
// | * * | |
// + * ** + +
// | * * | |
// | * * | |
// | ** * *** | |
// | * * * * | |
// +---------*--------*+---------+--**-**--+---------+---------+---------+---------+
//
// Γ(x)=int[t=0..∞]{e^-t*t^(x-1)*dt}
// Γ(n)=(n-1)!
// Γ(n+1)=n!
// =n*Γ(n)
//
// x<0のとき
// Γ(x)*Γ(1-x)=π/sin(π*x)
// で1<xにする
// Γ(x)=π/sin(π*x)/Γ(1-x)
// =π/sin(π*x)/e^lgamma(1-x)
//
// x==-0のとき
// -∞
//
// x==+0のとき
// +∞
//
// 0<xのとき
// Γ(x)=e^lgamma(x)
//
public final EFP tgamma () {
return this.tgamma (this);
} //efp.tgamma()
public final EFP tgamma (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = (xf == (P | Z) || xf == (P | I) ? P | I : //tgamma(+0)=tgamma(+Inf)=+Inf
xf == (M | Z) ? M | I : //tgamma(-0)=-Inf
N); //tgamma(NaN)=tgamma(-Inf)=NaN
return this;
}
//±0,±Inf,NaN以外
this.inner ();
if (xf < 0) { //x<0
EFP t = new EFP ().mul (PI, x).sin (); //sin(π*x)
this.negdec (x).lgamma ().exp ().mul (t).rcpdiv (PI); //π/(e^lgamma(1-x)*sin(π*x))
} else { //0<x
this.lgamma (x).exp (); //e^lgamma(x)
}
return this.outer ().finish ();
} //efp.tgamma(EFP)
//------------------------------------------------------------------------
//s = x.toString ()
// 10進数文字列化
//
// 絶対値が1以上で整数部が有効bit数を表現するのに十分な桁数に収まるとき
// 指数部を付けずに出力する
// 小数部の末尾の0を省略する
// 小数部がすべて省略されたときは小数点も省略する
// 絶対値が1未満で整数部の0と小数部を合わせて有効bit数を表現するのに十分な桁数+3桁に収まるとき
// 指数部を付けずに出力する
// 小数部の末尾の0を省略する
// それ以外
// 整数部が1~9の浮動小数点形式で出力する
//
@Override public String toString () {
int xf = this.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
return (xf == (P | Z) ? "0" :
xf == (M | Z) ? "-0" :
xf == (P | I) ? "Infinity" :
xf == (M | I) ? "-Infinity" :
xf << 3 < 0 ? "NaN" : "???");
}
//±0,±Inf,NaN以外
this.inner ();
EFP x = new EFP ().iabs (this); //絶対値
//10進数で表現したときの指数部を求める
// 10^e<=x<10^(e+1)となるeを求める
int e = (int) Math.floor ((double) x.epp * 0.30102999566398119521373889472); //log10(2)
//10^-eを掛けて1<=x<10にする
// 非正規化数の最小値から正規化数の最大値まで処理できなければならない
// 10^-eを計算してからまとめて掛ける方法は10^-eがオーバーフローするおそれがあるので不可
if (0 < e) { //10<=x
x.imul (EFP_TEN_M16QR[e & 15]);
if (16 <= e) {
x.imul (EFP_TEN_M16QR[16 + (e >> 4 & 15)]);
if (256 <= e) {
x.imul (EFP_TEN_M16QR[32 + (e >> 8 & 15)]);
if (4096 <= e) {
x.imul (EFP_TEN_M16QR[48 + (e >> 12)]);
}
}
}
} else if (e < 0) { //x<1
x.imul (EFP_TEN_P16QR[-e & 15]);
if (e <= -16) {
x.imul (EFP_TEN_P16QR[16 + (-e >> 4 & 15)]);
if (e <= -256) {
x.imul (EFP_TEN_P16QR[32 + (-e >> 8 & 15)]);
if (e <= -4096) {
x.imul (EFP_TEN_P16QR[48 + (-e >> 12)]);
}
}
}
}
this.outer ();
//整数部2桁、小数部EFP_DECIMAL_PREC+4&-4桁の10進数に変換する
// 1<=x<10なのでw[1]が先頭になるはずだが誤差で前後にずれる可能性がある
// 小数部を10000倍して整数部を引くことを繰り返すため、桁数に余裕のない浮動小数点数のまま行うと情報落ちが発生して誤差が蓄積する
// 固定小数点に切り替えて誤差なしで計算する
int[] w = new int[2 + (EFP_DECIMAL_PREC + 4 & -4)];
{
int t = 31 - x.epp;
long x1 = x.dvl >>> t; //上位32bitが整数部、下位32bitが小数部
long x2 = x.dvl << -t | x.cvl >>> t; //tは誤差を考慮しても最大32、x.cvlは下位32bitが0なのではみ出さない
long x3 = x2 & 0xffffffffL;
x2 >>>= 32;
t = XEiJ.FMT_BCD4[(int) (x1 >>> 32)]; //整数部
w[0] = t >> 4;
w[1] = t & 15;
for (int i = 2; i < 2 + (EFP_DECIMAL_PREC + 4 & -4); i += 4) {
x3 *= 10000L;
x2 = x2 * 10000L + (x3 >>> 32);
x3 &= 0xffffffffL;
x1 = (x1 & 0xffffffffL) * 10000L + (x2 >>> 32);
x2 &= 0xffffffffL;
t = XEiJ.FMT_BCD4[(int) (x1 >>> 32)]; //整数部
w[i ] = t >> 12;
w[i + 1] = t >> 8 & 15;
w[i + 2] = t >> 4 & 15;
w[i + 3] = t & 15;
}
}
//先頭の位置を確認する
// w[h]が先頭(0でない最初の数字)の位置
int h = w[0] != 0 ? 0 : w[1] != 0 ? 1 : 2;
//EFP_DECIMAL_PREC+1桁目を四捨五入する
int o = h + EFP_DECIMAL_PREC; //w[o]は四捨五入する桁の位置。w[]の範囲内
if (5 <= w[o]) {
int i = o;
while (10 <= ++w[--i]) {
w[i] = 0;
}
if (i < h) { //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
h--; //先頭を左にずらす
o--; //末尾を左にずらす
}
}
//先頭の位置に応じて指数部を更新する
// w[h]が整数部、w[h+1..o-1]が小数部。10^eの小数点はw[h]の右側。整数部の桁数はe+1桁
e -= h - 1;
//末尾の位置を確認する
// w[o-1]が末尾(0でない最後の数字)の位置
while (w[o - 1] == 0) { //全体は0ではないので必ず止まる。小数点よりも左側で止まる場合があることに注意
o--;
}
//文字列に変換する
StringBuilder sb = new StringBuilder ();
//符号を付ける
if (xf < 0) {
sb.append ('-');
}
//指数形式にするかどうか選択する
if (0 <= e && e < EFP_DECIMAL_PREC) { //1<=x<10^EFP_DECIMAL_PREC。指数形式にしない
do {
sb.append ((char) ('0' + w[h++])); //整数部。末尾の位置に関係なく1の位まで書く
} while (0 <= --e);
if (h < o) { //小数部がある
sb.append ('.'); //小数部があるときだけ小数点を書く
do {
sb.append ((char) ('0' + w[h++])); //小数部
} while (h < o);
}
} else if (-4 <= e && e < 0) { //10^-4<=x<1。指数形式にしない
sb.append ('0'); //整数部の0
sb.append ('.'); //小数点
while (++e < 0) {
sb.append ('0'); //小数部の先頭の0の並び
}
do {
sb.append ((char) ('0' + w[h++])); //小数部
} while (h < o);
} else { //x<10^-4または10^EFP_DECIMAL_PREC<=x。指数形式にする
sb.append ((char) ('0' + w[h++])); //整数部
if (h < o) { //小数部がある
sb.append ('.'); //小数部があるときだけ小数点を書く
do {
sb.append ((char) ('0' + w[h++])); //小数部
} while (h < o);
}
sb.append ('e'); //指数部の始まり
if (false) {
sb.append (e);
} else {
if (e < 0) {
sb.append ('-'); //指数部の負符号
e = -e;
} else {
sb.append ('+'); //指数部の正符号
}
e = XEiJ.fmtBcd8 (e);
int t = Integer.numberOfLeadingZeros (e);
if (t <= 27) {
if (t <= 23) {
if (t <= 19) {
if (t <= 15) {
sb.append ((char) ('0' + (e >>> 16 & 15)));
}
sb.append ((char) ('0' + (e >>> 12 & 15)));
}
sb.append ((char) ('0' + (e >>> 8 & 15)));
}
sb.append ((char) ('0' + (e >>> 4 & 15)));
}
sb.append ((char) ('0' + (e & 15)));
}
}
return sb.toString ();
} //efp.toString()
//------------------------------------------------------------------------
//x = x.trunc ()
// x=trunc(x)
//y = y.trunc (x)
// y=trunc(x)
// 切り落とし truncate
//
// グラフ
// perl -e "use Graph;$g=new Graph();$g->grid();$g->func(sub{int($_[0])});print$g"
// echo read("../misc/efp.gp");graph(truncate) | gp -q
// +---------+---------+---------+---------+---------+---------+---------+---------*
// | | |
// | | |
// | | |
// | | |
// + + ***********
// | | |
// | | |
// | | |
// | | |
// + + *********** +
// | | |
// | | |
// | | |
// | | |
// + + *********** +
// | | |
// | | |
// | | |
// | | |
// +---------+---------+---------*********************---------+---------+---------+
// | | |
// | | |
// | | |
// | | |
// + *********** + +
// | | |
// | | |
// | | |
// | | |
// + *********** + +
// | | |
// | | |
// | | |
// | | |
// *********** + +
// | | |
// | | |
// | | |
// | | |
// *---------+---------+---------+---------+---------+---------+---------+---------+
//
// ±0,±Inf,NaN そのまま
// e<=-1 すべて小数部なので±0
// 0<=e&&e<LEN-1 整数部と小数部が両方あるので小数部を消す
// LEN-1<=e すべて整数部なのでそのまま
//
public final EFP trunc () {
return trunc (this);
} //efp.trunc()
public final EFP trunc (EFP x) { //1.6ns
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
this.flg = xf;
return this;
}
//±0,±Inf,NaN以外
int xe = x.epp;
if (xe < 0) { //すべて小数部
epbFpsr |= EPB_FPSR_X2; //不正確な結果
this.flg = xf | Z; //±0
return this;
}
long xd = x.dvl;
long xc = x.cvl;
if (xe <= 63) { //0..63。dの途中または末尾まで整数部
long m = MSB >> xe; //整数部のマスク。符号に注意
if ((xd & ~m | xc) != 0L) { //小数部が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
xd &= m; //小数部を切り捨てる
xc = 0L;
}
} else if (xe <= LEN - 2) { //64..90。cの途中まで整数部
long m = MSB >> xe; //整数部のマスク。符号に注意
if ((xc & ~m) != 0L) { //小数部が0ではない
epbFpsr |= EPB_FPSR_X2; //不正確な結果
xc &= m; //小数部を切り捨てる
}
}
//すべて整数部のときはそのまま
return this.finish (xf, xe, xd, xc, 0L);
} //efp.trunc(EFP)
//------------------------------------------------------------------------
//x = x.ulp ()
// x=ulp(x)
//y = y.ulp (x)
// y=ulp(x)
// ulp
//
// 最下位bitの単位(ulp;unit last place)
// nextup(abs(x))-abs(x)
// ulp(±0)=指数部が最小の値, ulp(±Inf)=±Inf, ulp(NaN)=NaN
//
public final EFP ulp () {
return this.ulp (this);
}; //efp.ulp()
public final EFP ulp (EFP x) {
int xf = x.flg;
if (xf << 1 != 0) { //±0,±Inf,NaN
if (xf << 1 < 0) { //±0
this.flg = P;
this.epp = -32768;
this.dvl = MSB;
this.cvl = 0L;
} else {
this.flg = xf & ~M;
}
return this;
}
//±0,±Inf,NaN以外
this.flg = P;
this.epp = x.epp - (LEN - 1);
this.dvl = MSB;
this.cvl = 0L;
return this;
}; //efp.ulp(EFP)
} //class EFP
//------------------------------------------------------------------------
//コプロセッサインタフェイス
//
// CIR(コプロセッサインタフェイスレジスタ)を介して浮動小数点命令を対話形式で実行する
// on-chip FPUとやることは同じだが、命令の中断、保存、復元、再開ができる
// 浮動小数点命令をコマンドワードで分類するところまではon-chip FPUと同じ
// そこからさらに命令の処理段階で分類する
//
// CPU空間(FC=7)
// 0x...0.... Breakpoint Acknowledge
// 0x...1.... Access Level Control
// 0x...2.... Coprocessor Communications
// 0x00020000 id=0
// 0x00022000 id=1 MC68881/MC68882
// 0x00024000 id=2
// 0x00026000 id=3
// 0x00028000 id=4
// 0x0002a000 id=5
// 0x0002c000 id=6
// 0x0002e000 id=7
// 0x...f.... Interrupt Acknowledge
//
// 拡張ボード
// 0x00e9e000 JP1 数値演算プロセッサボード(CZ-6BP1/CZ-6BP1A)
// 0x00e9e080 JP2 数値演算プロセッサボード(CZ-6BP1/CZ-6BP1A)
//
// FSAVE
// $04 save CIRから1ワードのフォーマットワードを読み出す
// $01xxが返ったときはカムアゲインなので読み直す
// MC68882のフォーマットワードは$00xx、$1F38、$1FD4のいずれか
// $00xxはヌルステート。xxは無効。ヌルステートフレームのサイズは0バイト
// $1F38はアイドルステート。アイドルステートフレームのサイズは$38=56バイト
// $1FD4はビジーステート。ビジーステートフレームのサイズは$D4=212バイト
// ヌルステートのときはここで終わり
// $10 operand CIRからステートフレームを読み出す
// FSAVEはプレデクリメントが前提なのでロング単位で逆順に読み出される
// スタックにステートフレームをプッシュする
// スタックにフォーマットワード<<16をプッシュする
// FRESTORE
// スタックからフォーマットワード<<16をポップする
// $06 restore CIRにフォーマットワードを書き込む
// $06 restore CIRからフォーマットワードを読み出す
// 書き込んだフォーマットワードがそのまま返ればよい。$02xxが返ったときは不正なフォーマットワードなのでここで失敗
// スタックからステートフレームをポップする
// $10 operand CIRにステートフレームを書き込む
// FRESTOREはポストインクリメントが前提なのでロング単位で正順に書き込む
// 異常なステートフレームをリストアすると、マニュアルにないレスポンスが返ったり、オペランドCIRのアクセスがプロトコル違反ではなくてバスエラーになったり、かなりおかしなことになる
// $06 restore CIRにヌルステートの$0000を書き込むとリセットされる
// fp0-fp7はすべてNon-signaling NaNになり、FPCRとFPSRはゼロクリアされる
// --------------------------------
// > cir 00 .
// 0802
// > cir 0a 4000 fmove.l <ea>,fp0
// > cir 00 ....
// 9504 8900 8900 8900
// > cir 10 00000001
// > cir 00 ....
// 0802 0802 0802 0802
// > cir 0a 6000 fmove.l fp0,<ea>
// > cir 00 ....
// 8900 B104 0802 0802
// > cir 10 .
// 00000001
// > cir 00 ....
// 0802 0802 0802 0802
// > cir 0a 6000 fmove.l fp0,<ea>
// > cir 04 . fsave
// 1F38
// > cir 10 ..............
// 3C0EFFFF 00000001 00000000 00000002 FFFF0000 3FFF0000 20000000 00000000 00000000 00000000 00000200 60000000 0F800000 60006000
// > cir 00 ....
// 0802 0802 0802 0802
// > cir 06 1F38 frestore
// > cir 06 .
// 1F38
// > cir 10 60006000 0F800000 60000000 00000200 00000000 00000000 00000000 20000000 3FFF0000 FFFF0000 00000002 00000000 00000001 3C0EFFFF
// > cir 00 ....
// 8900 B104 0802 0802 fmove.l fp0,<ea>の続き
// > cir 10 .
// 00000001
// > cir 00 ....
// 0802 0802 0802 0802
// --------------------------------
public static final boolean CIR_DEBUG_TRACE = false;
//CIR
// 0x00 word read response CIR
// 0x02 word write control CIR
// 0x04 word read save CIR
// 0x06 word read write restore CIR
// 0x08 word read write operation word CIR MC68882のみ。MC68881ではwriteは無視、readは-1
// 0x0a word write command CIR