[PHP-users 28032] Re: 整数の下限

SAISHO Kazuhiro ml @ saisho.info
2006年 1月 5日 (木) 16:48:48 JST


税所です。
ご返信ありがとうございます。

[PHP-users 28028]
> 大垣です。

> こう言った場合の動作が気になるのであればソースを見るのが
> 一番簡単です。以下のコードはPHP 5.1.1のコードですが他のバー
> ジョンでもこの部分は変わらないと思います。
> 
> > var_dump (-2147483647 - 1);  # int(-2147483648)
>> 
>         if (op1->type == IS_LONG && op2->type == IS_LONG) {
>                 long lval = op1->value.lval - op2->value.lval;
> 
>                 /* check for overflow by comparing sign bits */
>                 if ( (op1->value.lval & LONG_SIGN_MASK) 
>                             != (op2->value.lval & LONG_SIGN_MASK)
>                         && (op1->value.lval & LONG_SIGN_MASK) 
>                             != (lval & LONG_SIGN_MASK)) {
> 
>                         result->value.dval = (double) op1->value.lval - (double) op2->value.lval;
>                         result->type = IS_DOUBLE;
>                 } else {
>                         result->value.lval = lval;
>                         result->type = IS_LONG;
>                 }
>                 return SUCCESS;
>         }
> 
> となっているのでアンダーフローチェックに引っかからないです。
> 
> > var_dump (-2147483648    );  # float(-2147483648)
>> 
> <ST_IN_SCRIPTING>{LNUM} {
>         errno = 0;
>         zendlval->value.lval = strtol(yytext, NULL, 0);
>         if (errno == ERANGE) { /* overflow */
>                 zendlval->value.dval = zend_strtod(yytext, NULL);
>                 zendlval->type = IS_DOUBLE;
>                 return T_DNUMBER;
>         } else {
>                 zendlval->type = IS_LONG;
>                 return T_LNUMBER;
>         }
> }
> 
> となっているのでERANGEがセットされているのでfloatになっているのだと思います。
> お使いの環境では
> 
> strtol("-2147483648", NULL, 0)
> 
> でerrnoにERANGEが設定されるのだと思います。

前者は zend_operators.c に、後者は zend_language_scanner.l に、
それぞれ記述されていますね。
でも私がそこに辿り着けたのは、大垣さんからご提示戴いたコードを
キーワードにしてファイルを検索したからにすぎません。
初めに質問させて戴いたような動作が気になるからといって、
どのソースを見ればいいかということは決して「簡単」ではないと
思いますが、如何でしょうか?
どうすればこのファイルのこのコードに辿り着くことができたのでしょうか?

ところで、前者の
>                 if ( (op1->value.lval & LONG_SIGN_MASK) 
>                             != (op2->value.lval & LONG_SIGN_MASK)
>                         && (op1->value.lval & LONG_SIGN_MASK) 
>                             != (lval & LONG_SIGN_MASK)) {
この部分は、バージョン4.4.1では、
                if ( (op1->value.lval & LONG_MIN) 
                            != (op2->value.lval & LONG_MIN)
                        && (op1->value.lval & LONG_MIN) 
                            != (lval & LONG_MIN)) {
このようになっていました。
つまり、
5.1.1 では LONG_SIGN_MASK
4.4.1 では LONG_MIN
になっています。
#define LONG_SIGN_MASK (1L << (8*sizeof(long)-1))
#define LONG_MIN (- LONG_MAX - 1)
とのことのようですので、
sizeof(long) の返り値が「4」であればしっくりいくような気がしますが、
この「long」とはいったい何でしょうか?
検索しようにも「long」という単語はたくさんありすぎて
絞り込むことができません。ご教授戴けましたら幸いです。
宜しくお願い致します。

--
税所 一弘 <ml @ saisho.info>



PHP-users メーリングリストの案内