アプリ版:「スタンプのみでお礼する」機能のリリースについて

int a;
double d;
d = 1.15 - 1.1;
a = (int)(d * 20);

この結果でaの値に1を期待しているのですが。0.9999になって結果が0になってしまいます。
他関数などを使用して良いプログラミング例はありますか?

それか、コンパイラの設定で桁数を指定して丸め込んだり出来れば解決しそうなのですが。

A 回答 (8件)

普通は、四捨五入に類することをやります。



a = d * 20.0 + 0.05;
(この 0.05 を必要な精度の桁数で決定する。この場合だと、小数点第2位で四捨五入)

あと、気になるところが。
> a = d * 20.0;
> これだと、コンパイルエラーです。
これは、C言語の正しい書き方です。
これでコンパイルエラーになるコンパイラは、今は存在しないと思いますが。

また、
> a = (int)(d * 20.0);
> だと、intがそれぞれにかかって、
> 結局 0 * 20 と同じ事で。
> =0

これも、int がそれぞにかかるのではなくて、
d * 20.0 の計算結果が、誤差の関係で、1.0 にならなかったから、切り捨てられて 0 になっているだけです。

一般に、double を int に代入するのに、キャストは不要です。
ですから、
a = d * 20.0 + 0.05;
という式も、右辺の式を double で計算した後、暗黙のキャストで int 型の a に普通に代入されます。

この回答への補足

ありがとうございます。
四捨五入方法、使ってみます。

C#でデバッグしてみましたが、
a = d * 20.0;は、
「型'double'を'int'に暗黙的に変換できません。明示的な変換が存在します。(castが不足していないかどうかを確認してください)」
といって警告ではなくエラーになりました。



>これも、int がそれぞにかかるのではなくて、
d * 20.0 の計算結果が、誤差の関係で、1.0 にならなかったから、切り捨てられて 0 になっているだけです。

たしかにそうなりました。

補足日時:2007/05/17 09:21
    • good
    • 2

がると申します。


小数点以下、を使うことを避けられてみては如何でしょうか?
素直に「整数のみ」で扱えるようにして、必要に応じて「表示だけ切り替える」のが、一番確実です。
浮動小数点というものは「誤差があって当たり前」のものですから。

小細工で「今回の結果を無理矢理1にすること」は可能でしょうけれども、同じ小細工を別の計算式でやると、大抵「やっぱり思ったとおりにいかない」とか言う話になり、わやくちゃになっちゃうモノなので。
    • good
    • 3

★スピードが要求されるのならばすべて int 型の整数で計算します。


・float、double 型よりも整数型の方が高速です。
 よって、100 倍した数値を int 型で表して計算すればよい。

つまり:
int a;
int d;

d = 115 - 110; ←100倍した値で計算。
a = (d * 20);
a ←100. になるが利用するときは 100 で割る。このときに float、double 型で計算する。

printf( "%lf\n", ((double)a / 100) ); ←ここで double 型にキャストして 100 で割る。

その他:
・浮動小数点は小数部を 2 進数で表すため数学的にきっちりした結果にはなりません。
 1/2、1/4、1/8、1/16、1/32…という数の合計が正確に表せる数です。
 つまり、
 0.03125
 0.06250
 0.09375
 0.12500
 0.15625
 0.18750
 0.21875
 0.25000
  :
 という数値だけが誤差がなく数を表せるのです。
・スピードが要求されるような場面では、出来るかぎり int 型の整数値を利用して下さい。
 小数として参照する直前で 100 で割るようにすればよい。または 1000 倍、10000倍にして
 計算して参照する直前で 1000、10000 で割ればよい。精度も良くなりますし、高速です。
・以上。参考に!

この回答への補足

なるほど~。
小数の仕組みわかりました。

補足日時:2007/05/17 09:36
    • good
    • 4

doubleからintに変換するときにマクロを使うとか。


#defineONROUND(a)(int)(((a)<0.0)?((a)-0.5):((a)+0.5))
な~んてね・・・
a = ONROUND(d * 20.0);
でどうでしょ?
    • good
    • 0

 double は、浮動小数点型ですので、仕様上そうなります。


 a を 1 として取り出したいのであれば、一旦、d*20 を
有効数字 小数点以下2桁の文字列にして、それを int で
読み込むのは、どうでしょうか。

int a;
double b,d;
char bb[20];

d = 1.15 - 1.1;
b = d*20.0;
sprintf(bb,"%.2lf",b);
sscanf(bb,"%d",&a);

この回答への補足

なるほど~。使えますね。
ですが、制御機器のため、スピードが要求されるので、
惜しくも、sprintfやsscanfが使えないのです。

補足日時:2007/05/16 17:09
    • good
    • 0

一介のデザイナーでプログラマではないので自信はありませんが・・・。



「プログラミング言語C」で2番目に登場する華氏の温度から摂氏の温度を求めるプログラム。

celsius = 5 * (fahr - 32) / 9;
celsius = (fahr - 32) * 5 / 9;

確か、下ではなく上の書き方をしていましたよね。

(下の書き方は)
「5 と 9 は整数だから、 5/9 は切り捨てられてゼロとなり、もちろんすべての摂氏温度がゼロになってしまう。」
(「プログラミング言語C」13頁)

この例に倣うならば・・・

Private Sub Command1_Click()
  Dim a As Integer
  Dim d As Double
  
  d = (115 - 110) / 100
  a = Int(d * 20)
  MsgBox a
End Sub

VB6.0 でも C でも通貨型を使わなければ同じことなのでVB6.0でテストしてみました。

なお、プロのプログラマの方の回答もお待ち下さい。

この回答への補足

これも使えますね。でも、こういう式を使った部分が、大量にありまして、ちょっと手作業が厳しい状態です。

少なければ私もこれでやろうかなと思ってました。

補足日時:2007/05/16 17:11
    • good
    • 0

たいていの処理系で double の値は「2進数に基づく浮動小数」で表現されるので, 2^-n という形でないと正確に表すことができません. そのようなものを有限のビット数で表現しなければならないので, 切り捨てられたり切り上げられたりします. これは double など浮動小数を使うときには常についてまわる問題なので, プログラムを書くときにきちんと注意する必要があります.


で, 対策ですが....
・そもそも double なんて使わない: 可能であればこれが最も簡単
・DBL_EPSILON を考慮してプログラムを書く: 面倒
・うまくいく関数たちを使う: 存在するかどうかは知りません
・C を使わない: C# なら OK だったと思う
かなぁ? この辺を処理する設定は, 普通はないと思います.

この回答への補足

いちお、doubleをやめて、floatにしたら、うまくいきました。
0.04999のいい具合のとこで四捨五入されたからだとおもいます。

Cでも、C#でも、Excelでも、やはり0.0499・・・82になりました。

日立のコンパイラのマニュアル見たら、小数点を切り捨てるか四捨五入かというのと、有効数字の桁数を設定するなんて書いてあったのですが、設定場所が見当たらず、日立に問い合わせ中です。

補足日時:2007/05/16 17:06
    • good
    • 0

d * 20.0



にするとどうなる?

この回答への補足

a = d * 20.0;
これだと、コンパイルエラーです。

a = (int)(d * 20.0);
だと、intがそれぞれにかかって、
結局
0 * 20
と同じ事で。
=0
になりました。

補足日時:2007/05/16 17:00
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!