double d = 100;
int i = (int)d;
double d = _tcstod(_T(100), NULL);
int i = (int)d;
極端な例ですが、上記の場合、
iが想定している値にならないケースが発生することはあるのでしょうか?
XP上のVisual C++ 2008では、どちらもiの値は100になるのですが、
これ以外の値でも必ず同じ値になるのかはわかりませんし、
100のケースでも言語的にはどうなのかなと疑問に思っています。
このようなケースでも、四捨五入の処理を入れておくべきものなのでしょうか?
>このようなケースでも、四捨五入の処理を入れておくべきものなのでしょうか?
double d = _tcstod(_T(100), NULL);
int i = (int)d;// これは「九捨零入」なので、
「何捨何入」にするかはその目的によります。
「四捨五入」にしたかったらすればよろしいのではないでしょうか。
何が訊きたいのか微妙にはっきりしないけど
・ double の内部表現 100.0 は正確に int の 100 に変換できる
・文字列 100 が正確に double の内部表現 100.0 になるかは定かでない
(変換手段の実装次第:通常は「なる」としても問題ないと思われる)
任意の double 整数が int に変換可能か、といわれればそれは当然無理。
double d=2147483648.0;
int i=(int)d;
は当然ながら符号付き32bit数値に入りきらないので期待通りの値にならない。
Windows というか Intel/AMD CPU の浮動小数点数は IEEE574/IEC559 表記を採用
しているので、例えばこの辺のページを参照。
http://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%
95%B0
四捨五入が必要か?は要件次第。
(四捨五入でよいか、銀行丸めでなければならないか、も要件次第)
> ・文字列 100 が正確に double の内部表現 100.0 になるかは定かでない
> (変換手段の実装次第:通常は「なる」としても問題ないと思われる)
これはつまり、100が_tcstod()で99.999...になり、
それをintにキャストしたときに99になってしまっても
仕様的には文句は言えないということですね。
実は、内部で文字列に_tcstod()を使ってdouble値として返すコントロールがあり、
それを整数しか扱わないデータ用にもそのまま使いたいなと思っていて、
返ってくる値は整数文字列をdoubleにしただけのもののはずなので、
戻り値を無条件にintにキャストしてもよいのかなと疑問に感じていました。
99になってしまわないようにするだけなので、
本来は四捨五入である必要も無いのですが、
99.999...と返ってきてしまったものを100として解釈するためには、
どのようなキャストをするべきなのでしょうか?(DBL_EPSILONを使う?)
およそ世の中にあるありとあらゆる C/C++ 処理系すべての strtod 変換関数で
100 -> 100.0 という変換がなされるとは限らないか、という設問と
Visual C++ 2008 の strtod/wcstod で _T(100) が 99.999 になりうるか、
という設問では、内容が異なりすぎる。
後者であれば strtod の実装を検証してみればよいだけの話。
とりあえずウチの VS2005 の crt/src/strtod.c を見てみた。
実変換を行っている部分はアセンブラの _fltin2 でソースが無いっぽいっす。
ただ、ごくごく簡単にそういう変換関数の実装を想像するに
・変換結果が int の範囲に収まる
・変換前の文字列表記には小数点文字 . や指数文字 E が含まれない
のであれば、変換演算として実行される式は単純に
(直前までの桁)*10 + 注目中の桁
であって、この式中に現れるすべての値が exact である以上は精度落ちは無い、
つまり必ず 100.0 になり、絶対に 99.999 になるわけがない、
と思われるのだがどうだろうか。
# 責任持つ気まったく無し。
tetrapodさんが書かれているように
いかなる場合でもと言う話とVS2005ではと言う話では
考えるべき内容が異なりますよね。
現在の開発環境の範囲で保証したいのであれば、
その中で保証できるかを確認すれば良いのではと思います。
未来永劫保証しろと言うのは多分無理なので。
で、100がうまくいけはそれで良いの?
と言う話もあります。
2進数表現で実数を表現する限界がある以上は
うまく行かない数値もありますからその場合も含めて
と言う話ならそれなりに対策が必要になるかもしれません。
それこそ「何捨何入」にするかは目的次第と言う話なので
その判断はシステムの使用が理解できている人の仕事に
なると思います。
あう。
誤字が。
「システムの使用が」ではなくて「システムの仕様が」ですね。
若干補足させてもらうと
double 「数値D」 = _tcstod(「数値文字列」, NULL);
のとき、「数値D」には、「数値文字列」のあらわす、純粋に数学的数値が
入らない場合があります。
まぁ、それとは関係なく、そもそもint値が取得したいのならば
ユーザーが誤り無くint値を入力できるインターフェースを
使用すべきだと考えますが、どうでしょう。
若干補足させてもらうと
double 「数値D」 = _tcstod(「数値文字列」, NULL);
のとき、「数値D」には、「数値文字列」のあらわす、純粋に数学的数値が
入らない場合があります。
まぁ、それとは関係なく、そもそもlong値が取得したいのならば
ユーザーが誤り無くlong値を入力できるインターフェースを
使用すべきだと考えます。
double を int にキャストする時点で危険が伴うと思います。
必要に応じた処理を書くほうがよいかもしれません。
みなさんありがとうございます。
おとなしく、値をintで返すメンバ関数をコントロールに追加し、
「整数を扱うモードのときは、こっちの関数で値を取得すること」
という仕様にしておきます。