ときどきの雑記帖 RE* (新南口)
Never ending story
色々ダメ
glibc
glibcはなぜかリポジトリが Savannah Git Hosting になかったり色々ほかのものと違っていたのでメモ。
HomePage
Public Git Hosting
Public Git Hosting - glibc.git/summary
BgiDecimal
BigDecimal.setScaleのRoundingMode.UPがこんなに切り上がるわけがない #初心者 - Qiita
ちょっと気になったので調べてみた。
import java.math.BigDecimal;
import java.math.RoundingMode;
class Main {
public static void main(String[] args) {
System.out.println(
BigDecimal
.valueOf(1.000000000000001d)
.setScale(0, RoundingMode.UP));
System.out.println(
BigDecimal
.valueOf(1.000000000000001d)
.setScale(1, RoundingMode.UP));
System.out.println(
BigDecimal
.valueOf(1.000000000000001d)
.setScale(5, RoundingMode.UP));
System.out.println(
BigDecimal
.valueOf(1.000000000000001d)
.setScale(10, RoundingMode.UP));
System.out.println(
BigDecimal
.valueOf(1.000000000000001d)
.setScale(13, RoundingMode.UP));
}
}
2
1.1
1.00001
1.0000000001
1.0000000000001
ついでに RoundingMode.HALF_EVEN
も確かめてみる
import java.math.BigDecimal;
import java.math.RoundingMode;
class Main {
public static void main(String[] args) {
System.out.println(
BigDecimal
.valueOf(1.500000000000000d)
.setScale(0, RoundingMode.HALF_EVEN));
System.out.println(
BigDecimal
.valueOf(1.500000000000001d)
.setScale(0, RoundingMode.HALF_EVEN));
System.out.println(
BigDecimal
.valueOf(2.500000000000000d)
.setScale(0, RoundingMode.HALF_EVEN));
System.out.println(
BigDecimal
.valueOf(2.500000000000001d)
.setScale(0, RoundingMode.HALF_EVEN));
}
}
2
2
2
3
ふむ。
ドキュメントにはどう書かれているのかと見てみると
BigDecimal (Java Platform SE 6)
setScale(int newScale, RoundingMode roundingMode)
スケールが指定された値であり、かつスケールなしの値が、この BigDecimal のスケールなしの値と、 総体値を維持できる適当な 10 の累乗の積または商により決定される BigDecimal を返します。
なんやらよくわからん😓
こういうときは原文に。で見てみたが
BigDecimal (Java Platform SE 8 )
setScale(int newScale, RoundingMode roundingMode)
Returns a BigDecimal whose scale is the specified value, and whose unscaled value is determined by multiplying or dividing this BigDecimal’s unscaled value by the appropriate power of ten to maintain its overall value.
やっぱりよくわからん。 が、どうもExcelの ROUND 関数 - Microsoft サポート のような
ROUND 関数は、数値を四捨五入して指定された桁数にします。 たとえば、セル A1 が 23.7825 で、 その数値を小数点以下第 2 位に四捨五入するには、次の数式を使用します。
という、ある特定の桁に注目してそこで丸めを行うというものではなさそうな気がする。
- java - BigDecimalを用いても四捨五入されません。 - スタック・オーバーフロー
- how do i round a number to 6 significant figures in java? - Stack Overflow
- java - method to round to a certain amount of decimal places, according to a variable - Stack Overflow
- Four common pitfalls of the BigDecimal class and how to avoid them
- [Java] 指定した桁位置で四捨五入・切上げ・切捨てをする – Javaちょこっとリファレンス ブログ
- JavaのBigDecimalをまとめる(リストのBigDecimalの計算も)【2021年】 - きり丸の技術日記
- How to Round a Number to N Decimal Places in Java | Baeldung
ということで(謎) ソースコードを(ry
適当なキーワードで検索すると いくつか引っかかるのだけどさてどれを
OpenJDKのソースコードリポジトリは、どれを見ればいい? - CLOVER🍀
jdk7
jdk7u-jdk/src/share/classes/java/math/BigDecimal.java
まずはsetScaleをみると
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/math/BigDecimal.java#L2378
public BigDecimal setScale(int newScale, int roundingMode) {
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
int oldScale = this.scale;
if (newScale == oldScale) // easy case
return this;
if (this.signum() == 0) // zero can have any scale
return BigDecimal.valueOf(0, newScale);
long rs = this.intCompact;
if (newScale > oldScale) {
int raise = checkScale((long)newScale - oldScale);
BigInteger rb = null;
if (rs == INFLATED ||
(rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
rb = bigMultiplyPowerTen(raise);
return new BigDecimal(rb, rs, newScale,
(precision > 0) ? precision + raise : 0);
} else {
// newScale < oldScale -- drop some digits
// Can't predict the precision due to the effect of rounding.
int drop = checkScale((long)oldScale - newScale);
if (drop < LONG_TEN_POWERS_TABLE.length)
return divideAndRound(rs, this.intVal,
LONG_TEN_POWERS_TABLE[drop], null,
newScale, roundingMode, newScale);
else
return divideAndRound(rs, this.intVal,
INFLATED, bigTenToThe(drop),
newScale, roundingMode, newScale);
}
}
丸めの処理はこの関数ではなく呼び出しているdivideAndRound
でやっているようだ
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/math/BigDecimal.java#L1412
private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
long ldivisor, BigInteger bdivisor,
int scale, int roundingMode,
int preferredScale) {
boolean isRemainderZero; // record remainder is zero or not
int qsign; // quotient sign
long q = 0, r = 0; // store quotient & remainder in long
MutableBigInteger mq = null; // store quotient
MutableBigInteger mr = null; // store remainder
MutableBigInteger mdivisor = null;
boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);
if (isLongDivision) {
q = ldividend / ldivisor;
if (roundingMode == ROUND_DOWN && scale == preferredScale)
return new BigDecimal(null, q, scale, 0);
r = ldividend % ldivisor;
isRemainderZero = (r == 0);
qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
} else {
if (bdividend == null)
bdividend = BigInteger.valueOf(ldividend);
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
mq = new MutableBigInteger();
if (ldivisor != INFLATED) {
r = mdividend.divide(ldivisor, mq);
isRemainderZero = (r == 0);
qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
} else {
mdivisor = new MutableBigInteger(bdivisor.mag);
mr = mdividend.divide(mdivisor, mq);
isRemainderZero = mr.isZero();
qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
}
}
boolean increment = false;
if (!isRemainderZero) {
int cmpFracHalf;
/* Round as appropriate */
if (roundingMode == ROUND_UNNECESSARY) { // Rounding prohibited
throw new ArithmeticException("Rounding necessary");
} else if (roundingMode == ROUND_UP) { // Away from zero
increment = true;
} else if (roundingMode == ROUND_DOWN) { // Towards zero
increment = false;
} else if (roundingMode == ROUND_CEILING) { // Towards +infinity
increment = (qsign > 0);
} else if (roundingMode == ROUND_FLOOR) { // Towards -infinity
increment = (qsign < 0);
} else {
if (isLongDivision || ldivisor != INFLATED) {
if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
cmpFracHalf = 1; // 2 * r can't fit into long
} else {
cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
}
} else {
cmpFracHalf = mr.compareHalf(mdivisor);
}
if (cmpFracHalf < 0)
increment = false; // We're closer to higher digit
else if (cmpFracHalf > 0) // We're closer to lower digit
increment = true;
else if (roundingMode == ROUND_HALF_UP)
increment = true;
else if (roundingMode == ROUND_HALF_DOWN)
increment = false;
else // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();
}
}
BigDecimal res;
if (isLongDivision)
res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);
else {
if (increment)
mq.add(MutableBigInteger.ONE);
res = mq.toBigDecimal(qsign, scale);
}
if (isRemainderZero && preferredScale != scale)
res.stripZerosToMatchScale(preferredScale);
return res;
}
ざっと見た感じ、やはり指定された桁より下も無視していないように読める。
openjdk
GNU classpath
- Source for java.math.BigDecimal (GNU Classpath 0.95 Documentation)
- gwt/user/super/com/google/gwt/emul/java/math/BigDecimal.java
FORTRAN Compiler on IBM 704
STATEC
作業領域BETA
をちょっと追っかけ
R00500 STQ BETA,B 4F14214 clear BETA
TXI R00700,B,-1 4F14215
R00700 TXH R00500,B,0 4F14216
*
CLA 3LBAR 4F14217
STD R01700 4F14218
STD R06200 4F14219
*
R01000 CLA LAMBDA,A ADD INTO GAMMA COUNTERS 4F14220
PAX 0,B 4F14221
CLA BETA,B 4F14222
ADD BETAD1 (-3)*2**18+(-3) 4F14223 BETAD1 OCT 77775077775
STD BETA,B 4F14224
STA BETA,B 4F14225
TXI R01700,A,-3 4F14226
R01700 TXH R01000,A,0 -3L IN XA AT END 4F14227
*go loop
*
R01800 TXH R04200,A,-6 EXIT FROM SINGLE ELEMENT REDUCTION 4F14228
CLA LAMBDA-3,A 4F14229
PAX 0,B 4F14230
CLA BETA,B 4F14231
SUB BETAD1 4F14232 BETAD1 OCT 77775077775
TZE R02600 4F14233
TXI R01800,A,3 4F14234
*go loop
*
R02600 LDQ LAMBDA-2,A SINGLE ELEMENT 4F14235
LGL 6 EXAMINE OPERATION 4F14236
SUB 11Z 4F14237 11Z OCT 40 '-'
TNZ R03200 4F14238
TXI R01800,A,3 4F14239
*go loop
*
R03200 CAL MASK1 SINGLE ELEMENT, NON-UNARY OP 4F14240 MASK1 OCT -377777700000
ANS LAMBDA-3,A EXTRACT TAGS AND STORE BACK 4F14241
CLA LAMBDA-6,A 4F14242
ORA LAMBDA-3,A 4F14243
SLW LAMBDA-6,A 4F14244
CAL LAMBDA-2,A EXTRACT FS BITS AND STORE BACK 4F14245
ANA MASK5 4F14246 MASK5 OCT 37777600
ORS LAMBDA-5,A 4F14247
CAL LAMBDA-1,A STORE BACK SYMBOL 4F14248
SLW LAMBDA-4,A 4F14249
STZ BETA,B REDUCE GAMMA COUNT TO 0 4F14250
STZ LAMBDA-3,A CLEAR TAG WORD 4F14251
TXI R01800,A,3 RESUME SCAN-BACK 4F14252
*go loop
R04200 STZ G 4F14253
LXA L(0),7 CLEAR XA,XB,XC 4F14254
*
R04500 CLA BETA,B SET ORIGINS OF SCRIPL TABLE 4F14255
BETAD1
BETAD1、以前見たときはコメントにもある
(-3)*2**18+(-3)
がどういうことなのかよくわからなかったけど、
car部とcdr部(マテ)以外は0ということなのね。
carとcdrの最後の桁が7じゃなくて5なのはまだわからんけど
BETAD1 OCT 77775077775
0 3 18 21 35
+---+---------------+---+---------------+
|000|111111111111101|000|111111111111101|
+---+---------------+---+---------------+
MASK1
こいつはcdr部だけが0で他はすべて1
MASK1 OCT -377777700000
0 3 18 21 35
+---+---------------+---+---------------+
|111|111111111111111|111|000000000000000|
+---+---------------+---+---------------+
MASK5
これはぜんぜんわからん
MASK5 OCT 37777600
0 3 18 21 35
+---+---------------+---+---------------+
|000|000000000011111|111|111111110000000|
+---+---------------+---+---------------+
今後の言語、ポインタの逆参照も後置にしてくれないかなぁ。
— yoh2 (@yoh2_sdj) March 28, 2024
(*p).foo より p*.foo と書きたい。
C/C++ の -> ? あれは一段まではいいけど二段になると結局 (**pp).foo や (*p)->foo になるじゃない。
何気に今年SQLの生誕50周年なんですよね。でもイベントもないし誰にも祝ってもらえる様子もないのが、なんつうかSQLらしい。いつもそこにいるのが当たり前みたいな顔して座ってる人みたいな。 https://t.co/lMk3gCl8mM
— ミック (@copinemickmack) March 30, 2024