質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

4回答

3348閲覧

何故、商が少数で余りが負数になるのか

aaaaaaaa

総合スコア501

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2018/05/15 10:20

PHP_INT_MAXぼ値を超えた数値を割ると商が少数に余りが負数になります。負の余りなんてあったっけと思いつつ調べると、定義次第とありました。
例えば、3486784400 % 7は、498112057(商)...1(余り)ですが、PHPで計算すると498112057.57143(商)...-3(余り)となります。

なぜ、商が少数となり余りが負数になるのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/05/15 10:46 編集

《商が少数で余りが負数になる》事例の再現方法、実行環境を示してください。32bit環境なのか64bit環境なのかも添えて。
guest

回答4

0

ベストアンサー

PHPの/は左辺と右辺が整数(int)で、かつ、割りきれる場合のみ整数(int)を返し、それ以外は浮動小数点数(float)を返します。整数商を求めたい場合はintdiv()を使用してください。しかし、3486784400 % 7-3になる環境ではintdiv(3486784400, 7)はエラーになるでしょう。それを含めて、3486784400 % 7がなぜ-3になるのかを説明します。

3486784400 を 7 で割った余りは -3 ?

この演算結果は算術的には全く正しくありません。確かに定義によって剰余が負の数になる場合がありますが、それは左辺と右辺の少なくとも一方が負の数になる場合のみです。両辺が正の数の場合は必ず正の数になります。勝手に負の数になることはありませんし、そのような定義もされることはありません。

なんだ、PHPは算数も出来ないのか!とお思いでしょうが、違います。正確には、PHPはある数より大きい整数については算数が出来ない、です。このとある数はPHP_INT_MAXという定数で取得でき、OSやアーキテクチャによって固定で、通常は2147483647(32bit環境)か9223372036854775807(64bit環境)のどちらかです。

気付きましたか?34867844002147483647より大きい整数です。そのため、PHP_INT_MAX2147483647である環境では3486784400を整数として扱えません。そのため、整数の簡単な算数ですら、PHPは正確に出来ないのです。

では、実際どのような処理の結果-3というとんちんかんな答えを出してしまったのかを見ていきましょう。下記処理はPHP_INT_MAX2147483647の場合です。9223372036854775807では正しく1と答えてくれるので、該当しないことに注意してください。

まず、3486784400というリテラル表記ですが、整数(int)ではありませんPHP_INT_MAXを越えているため、PHPではこの表記の数を整数として扱えないからです。実際には何になるのかというと、var_dump()で確認できます。

var_dump(3486784400); // => float(3486784400)

そう、浮動小数点数(float)です。intdiv(3486784400, 7)がエラーになるのは、整数しか受け付けないintdiv()に浮動小数点数(float)を入れてしまったからです。そして、困ったことにPHPでの%の剰余計算も整数(int)同士の演算しか考慮していません。%はエラーにならない代わりに、左辺と右辺について「整数(int)に変換する」という処理をします。7は既に整数(int)ですので変換は起きませんが、3486784400は浮動小数点数(float)なので、整数(int)への変換が発生します。実際、整数(int)へ変換しようとするとどうなるのでしょうか?

var_dump((int)(3486784400)); // => int(-808182896)

謎の整数-808182896が出てきました。このようなPHP_INT_MAXを越えている場合どのような値になるかについて、PHPマニュアルでは結果は未定義とされています。未定義だから何でもあり、では面白くないので、ソースコードを追いかけてみましょう。整数(int)変換は途中色々あるのですが、範囲超えている浮動小数点数(float)の整数(int)への変換は最終的にzend_dval_to_lval_slow()で行われます。

ソースコード: Zend/zend_operators.c 3102行目 zend_dval_to_lval_slow()の定義(32bit) - PHP 7.2.6

やっていることは、2の32乗(4294967296)の剰余を求めて、符号無し整数(zend_ulong)にした後、符号有り整数(zend_long)、つまり、整数(int)にキャストしています(CのdoubleがPHPのfloat、Cのzend_longがPHPのintに対応し、zend_ulongはPHP上にはあらわれない)。

3486784400に対する4294967296の剰余は3486784400です。32bitの符号無し整数ではこれは表現可能ですので、このままの整数値になります。これを32bitの符号あり整数にキャストするわけですが、32bitの2の補数表現の環境では、4294967296を引いた数、つまり、-808182896になります。ただし、これらは環境依存であるため、全ての環境で同じような動作をするとは限らない事に注意してください。ここら辺はCをちょっと囓らないと難しいかも知れません。

とりあえず、環境によりますが、-808182896になることはわかりました。あとは-808182896 % 7が何になるかです。PHPの剰余の結果は左辺の符号と同じ符号で絶対値が右辺より小さくなるように求めるとなっていますので、答えは-3となるわけです。

※ 左辺が負の数の時に右辺も負の数になるかどうかは言語によって異なります。剰余演算 - Wikipediaに各言語の結果一覧がありますので、参考にしてみてください。

投稿2018/05/15 13:30

編集2018/05/15 13:32
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

なんか、WindowsじゃなくてLinux使えって事らしいですねー。

整数

整数のサイズはプラットフォームに依存しますが、 約 20 億 (32 ビット符号付) が一般的な値です。 64 ビットプラットフォームでの通常の最大値は、およそ 9*10^18 (900京) になります。

しかし PHP 7 より前のバージョンにおける Windows は例外で、Windows で PHP 7 より前のバージョンを使う場合はは常に 32 ビットとなります。 PHP は符号無し整数をサポートしていません。

整数のサイズは定数 PHP_INT_SIZE(※注:Byte数) で、 そして整数の最大値は定数 PHP_INT_MAX でそれぞれ決まります。 これらの定数は、PHP 5.0.5 以降で使えます。 PHP 7.0.0 以降では、整数の最小値を表す定数 PHP_INT_MIN が使えるようになりました。

うそつきー! Windows XAMPP PHP7.2.3 でも PHP_INT_SIZE は 4 で PHP_INT_MAX は 2147483647 ぞ!

PHP

1<?php 2$val = 3486784400; 3echo gettype($val) . "\n"; // ← 結果 double ウェウェウェ 4``` 5 6####追記 7 8% (moduler) は左辺がINTEGERでないとダメなので double になった 3486784400 を int に暗黙キャストするんだけど、オーバーフローして値がマイナスになるんだろうな。 9 10一方、商については double をそのまま割って型は double のまま。 11 12```PHP 13<?php 14$val = 3486784400; 15echo gettype($val) . "\n";   // ← double 16echo gettype($val % 7) . "\n"; // ← integer 17echo gettype($val / 7) . "\n"; // ← double 18```

投稿2018/05/15 11:11

編集2018/05/15 11:22
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/05/15 11:26

あー、そだったね、WindowsのXAMPPって、いまだに32bit版だったんだっけ…。
guest

0

なぜ、商が少数となり

PHPには整数除算が無くて、/は実数の除算なので割り切れない場合に商が小数になるのは当然です。

投稿2018/05/15 12:24

otn

総合スコア84553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Online PHP editor | output for 0iat0

php

1<?php 2 3echo 3486784400 % 7 . PHP_EOL; 4echo 3486784400 / 7 . PHP_EOL;

実行結果:
実行結果のスクリーンショット

質問文にあるような結果を導き出せないので、説明できません。

投稿2018/05/15 10:29

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問