doubleをintにキャスト

[戻る]
NOR 2010/08/24(火) 09:34:15
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のケースでも言語的にはどうなのかなと疑問に思っています。

このようなケースでも、四捨五入の処理を入れておくべきものなのでしょうか?

仲澤@失業者 2010/08/24(火) 11:42:50
>このようなケースでも、四捨五入の処理を入れておくべきものなのでしょうか?

double d = _tcstod(_T("100"), NULL);
int i = (int)d;// これは「九捨零入」なので、

「何捨何入」にするかはその目的によります。
「四捨五入」にしたかったらすればよろしいのではないでしょうか。

tetrapod 2010/08/24(火) 11:44:43
何が訊きたいのか微妙にはっきりしないけど
・ 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

四捨五入が必要か?は要件次第。
(四捨五入でよいか、銀行丸めでなければならないか、も要件次第)

NOR 2010/08/24(火) 12:33:19
> ・文字列 "100" が正確に double の内部表現 100.0 になるかは定かでない
>  (変換手段の実装次第:通常は「なる」としても問題ないと思われる)

これはつまり、"100"が_tcstod()で99.999...になり、
それをintにキャストしたときに99になってしまっても
仕様的には文句は言えないということですね。

実は、内部で文字列に_tcstod()を使ってdouble値として返すコントロールがあり、
それを整数しか扱わないデータ用にもそのまま使いたいなと思っていて、
返ってくる値は整数文字列をdoubleにしただけのもののはずなので、
戻り値を無条件にintにキャストしてもよいのかなと疑問に感じていました。

99になってしまわないようにするだけなので、
本来は四捨五入である必要も無いのですが、
99.999...と返ってきてしまったものを100として解釈するためには、
どのようなキャストをするべきなのでしょうか?(DBL_EPSILONを使う?)

tetrapod 2010/08/24(火) 13:50:40
およそ世の中にあるありとあらゆる 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 になるわけがない、
と思われるのだがどうだろうか。
# 責任持つ気まったく無し。

PATIO 2010/08/24(火) 15:18:40
tetrapodさんが書かれているように

いかなる場合でもと言う話とVS2005ではと言う話では
考えるべき内容が異なりますよね。

現在の開発環境の範囲で保証したいのであれば、
その中で保証できるかを確認すれば良いのではと思います。
未来永劫保証しろと言うのは多分無理なので。

で、100がうまくいけはそれで良いの?
と言う話もあります。
2進数表現で実数を表現する限界がある以上は
うまく行かない数値もありますからその場合も含めて
と言う話ならそれなりに対策が必要になるかもしれません。
それこそ「何捨何入」にするかは目的次第と言う話なので
その判断はシステムの使用が理解できている人の仕事に
なると思います。

PATIO 2010/08/24(火) 15:30:11
あう。

誤字が。

「システムの使用が」ではなくて「システムの仕様が」ですね。

仲澤@失業者 2010/08/24(火) 17:16:32
若干補足させてもらうと

double 「数値D」 = _tcstod(「数値文字列」, NULL);

のとき、「数値D」には、「数値文字列」のあらわす、純粋に数学的数値が
入らない場合があります。

まぁ、それとは関係なく、そもそもint値が取得したいのならば
ユーザーが誤り無くint値を入力できるインターフェースを
使用すべきだと考えますが、どうでしょう。

仲澤@失業者 2010/08/24(火) 17:16:36
若干補足させてもらうと

double 「数値D」 = _tcstod(「数値文字列」, NULL);

のとき、「数値D」には、「数値文字列」のあらわす、純粋に数学的数値が
入らない場合があります。

まぁ、それとは関係なく、そもそもlong値が取得したいのならば
ユーザーが誤り無くlong値を入力できるインターフェースを
使用すべきだと考えます。

かも 2010/08/24(火) 22:03:58
double を int にキャストする時点で危険が伴うと思います。
必要に応じた処理を書くほうがよいかもしれません。

NOR 2010/08/29(日) 15:18:03
[[解決]]
みなさんありがとうございます。

おとなしく、値をintで返すメンバ関数をコントロールに追加し、
「整数を扱うモードのときは、こっちの関数で値を取得すること」
という仕様にしておきます。

古いスレッドには追加発言できません。