ときどきの雑記帖 RE* (新南口)
dtoa 解読(1)
変数名
オリジナルの変数宣言はこんな感じになっていて、 中には使いまわしをしている変数もある(iとかjとか)
int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
spec_case, try_quick;
Long L;
int denorm;
ULong x;
Bigint *b, *b1, *delta, *mlo, *mhi, *S;
U d2, eps, u;
double ds;
char *s, *s0;
使い回しは理由があってのことなのだろうけど、プログラムが読みづらいことこの上ないので (役目が変わったところで)別の変数に切り分けたり 宣言の場所を関数の先頭から最初に使う直前にしたり 名前をその役目がわかるようなものにしたり 色々変えてみた。
int exponent;
int denormal;
if ((exponent = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
dval(&d2) = dval(&u);
word0(&d2) &= Frac_mask1;
word0(&d2) |= Exp_11;
たとえば↑のexponentとか(元はiだった)。 と言いつつもいくつかはどうにもいい名前が浮かばずそのままにしているものもあるし、 こんな名前(xxxx。もとはj)にしてしまったものもある。
int xxxx = bbits - exponent - 1;
printf("%d: xxxx=%d\n", __LINE__, xxxx);
int b2;
int b5;
int s2;
int s5;
if (xxxx >= 0) {
b2 = 0;
s2 = xxxx;
}
else {
b2 = -xxxx;
s2 = 0;
}
多倍長整数化したビット列に関するシフト量(たぶん)ではあるのだけど。
変換
実際のところ、あれやこれやの「最適化」と条件分けを除くと 変換のキモとなるのはここだけ(たぶん)
else
for(int ii = 1;; ii++) {
*s++ = dig = quorem(b, S) + '0';
if (!b->x[0] && b->wds <= 1) {
goto ret;
}
if (ii >= ilim)
break;
b = multadd(b, 10, 0);
if (b == NULL)
goto failed_malloc;
}
ある意味、二進小数から十進数への変換手順そのまま。
条件判定
ただ今回の場合は「それらしい」結果が得られたらそこで変換を切り上げるという ものなので、ここまで単純にはならない。
for(int ii = 1;;ii++) {
dig = quorem(b, S) + '0';
/* Do we yet have the shortest decimal string that will round to d? */
int jj = cmp(b, mlo);
Bigint *delta = diff(S, mhi);
if (delta == NULL)
goto failed_malloc;
int j1 = delta->sign ? 1 : cmp(b, delta);
printf("dig=%c, ii=%d, jj=%d, j1=%d, delta->sign=%d\n", dig, ii, jj, j1, delta->sign);
dprint(b);
dprint(delta);
Bfree(delta);
if (j1 == 0 && mode != 1 && !(word1(&u) & 1)) {
if (dig == '9')
goto round_9_up;
if (jj > 0)
dig++;
*s++ = dig;
goto ret;
}
if (jj < 0 || (jj == 0 && mode != 1 && !(word1(&u) & 1))) {
if (!b->x[0] && b->wds <= 1) {
goto accept_dig;
}
if (j1 > 0) {
b = lshift(b, 1);
if (b == NULL)
goto failed_malloc;
int j2 = cmp(b, S);
if ((j2 > 0 || (j2 == 0 && dig & 1))
&& dig++ == '9')
goto round_9_up;
}
accept_dig:
*s++ = dig;
goto ret;
}
if (j1 > 0) {
ここのループ変数の ii も元はiだったり。
それはさておき、Do we yet have the shortest decimal string that will round to d? とコメントにもある通り ここで変換が十分かを判定している(と思われる)のだが
next ≫ dtoa 解読 (2)