お世話になっています、DELPHI の入門者です。
実数の割り算をすると、数字によっては「nnn.99999・・・」などと
なる時がありますが、これを防ぐには、変数をどのタイプにすれば
良いのでしょうか?
今は Double にしています。
扱う数字は +0.000 〜 +999.999 の間しか使いません。
Delphi の Help で探してるのですが、見つかりません。
たぶん、自分の探し方が悪いんだと思いますが、
「こうだ!!・・・」と教えて頂ければ、うれしいです。
よろしくお願いします。
ご質問の意味がいまいち理解できません。
> これを防ぐには
1を3で割ると、どのような数なると期待しているんでしょうか?
大変、変な文になってしまいました。すいません。
割り算ではなく、引き算で出ています。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
public
Max_n: Double;
Min_n: Double;
Def_n: Double;
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
Max_n := StrtoFloat(P1_mae_RT.Text);
Min_n := StrtoFloat(P2_mae_RT.Text);
Def_n := Max_n - Min_n;
Def_mae_RT.Text := FloattoStr(Def_n);
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
上記で P1_mae_RT.Text には 80.4
P2_mae_RT.Text には 84.3
がはいっています。
すると、Def_mae_RT.Text には 3.89999 が表示されます。
このようになる数の組み合わせはめったに出ないのですが・・・
上記で、他にも変なところがあるかもしれません。
部分的で分かりにくいと思いますが、よろしくご指導ください。
すいません、数字の上下が違っていました、
P1_mae_RT.Text には 84.3
P2_mae_RT.Text には 80.4
です。
84.3 - 80.4 = 3.9 のはずが 3.899999・・・
よろしくお願いします。
Currency 型を調べてみて下さい.
しかし,個人的な意見としては,何故nnn.9999...となってはいけないの
か,最終的な表現がどうあればいいのかを十分考え,検討することをお勧
めします.
ご存知だとは思いますが,コンピュータによる実数の計算には誤差は
つきものです.紙の上での数学の計算とは違います.
極端な話,コンピュータでは,無限小も無限大という数も存在しません.
そして,10進数の有限小数の大部分は,2進数(コンピュータ内部表現)で
は無限小数となります.これが割り切れるはずの数がnnn.9999..となった
りする原因の一つです.
[例]
0.1 0.0001100110011....(2進数) 0.19999999.....(16進数)
>84.3 - 80.4 = 3.9 のはずが 3.899999・・・
例えば,これでしたら,小数点4桁目で四捨五入すれば,実用的には
十分ですよね.
早速のご指摘、有り難うございます。
「Currency 型」の所を読んでみます。
「xx.999・・・」この小数部「.999・・・」が実際の数か、誤差表示かを
判別するのが、めんどうだと思いましたので・・・
何かの言語で「10進演算」のような物が有ったように思いましたので、
Delphi でも有るかな〜と思いました。
元の数を 1000 倍し、小数部をなくし、整数演算してもだめでしょうか?
ちょっと試してみます。
アドバイス有り難うございました。
返信記入中に次が入っていました。
>小数点4桁目で四捨五入すれば,実用的には十分ですよね.
そうですね、これでやってみます。
有り難うございました。
BCD(2進化10進数)はデータベースの項目値,またDelphi6以上でしたら,
FMTBcdユニットを使用すれば可能です.
[例]
// usesにFMTBcdが必要
procedure TForm1.Button1Click(Sender: TObject);
var
A,B,C: TBCD;
begin
A:=DoubleToBcd(84.3);
B:=DoubleToBcd(80.4);
BcdSubtract(A,B,C);
ShowMessage(BCDToStr(C));
end;
>元の数を 1000 倍し、小数部をなくし、整数演算してもだめでしょうか?
結果が整数である保証があればですね.
DELPHI は Ver.7です。
「FMTBcdユニット」を使って[例]を参考にしてやってみます。
>結果が整数である保証があればですね
整数どうしの引き算なので結果は必ず整数?
今日はもう遅いので、結果は明日の夜に報告したいと思います。
BCD(2進化10進数)・・・たぶんOKですね?
お世話になっています。
「FMTBcdユニット」を使って[例]を参考にしてやってみました。
うまく行きました、手元のデータでは完璧に処理しています。
以下がその抜粋です。
==============================
If BcdCompare(Max_n , P1_n) = -1 then Max_n := P1_n;
If BcdCompare(Max_n , P2_n) = -1 then Max_n := P2_n;
If BcdCompare(Max_n , P3_n) = -1 then Max_n := P3_n;
If BcdCompare(Max_n , P4_n) = -1 then Max_n := P4_n;
If BcdCompare(Min_n , P1_n) = 1 then Min_n := P1_n;
If BcdCompare(Min_n , P2_n) = 1 then Min_n := P2_n;
If BcdCompare(Min_n , P3_n) = 1 then Min_n := P3_n;
If BcdCompare(Min_n , P4_n) = 1 then Min_n := P4_n;
BcdSubtract(Max_n , Min_n , Def_n);
BcdAdd(P1_n , P2_n , BCD_A);
BcdAdd(P3_n , P4_n , BCD_B);
BcdAdd(BCD_A , BCD_B , BCD_C);
BcdDivide(BCD_C , 4 , Ave_n);
Str_Ave := BCDToStr(Ave_n);
Str_Def := BCDToStr(Def_n);
==============================
最初、普通の IF 文でやっていたらエラーになり、調べたら
専用の BcdCompare が有ったので、それを使ったらすべてうまく
行きました。
IF 文の「=-1」と「=1」は 後々の理解のため明示しときました。
Mr.XRAY さんには色々と教えていただき、有り難うございました。
これで、解決しました。
うまくいったということで,それでいいとしますが,
10進演算(BCD演算)は,やはり特殊だと思います.もちろん,教育用などで
計算演習などのプログラムでは必要になることあるでしょう.
実数の座標軸を作成するプログラムを作成していますが,この時S_M_Hさん
のような誤差がでると,うまくいきません.しかし,実際の処理は四捨五入
(指定小数点以下の)等で処理しています.
目的によって使い分けが必要でしょうね.
でも,抜粋のコードは,この掲示板をご覧になる他の方にとっても参考に
なるでしょう.
お世話になっています。
今回の様な5桁以内の数字の処理であれば4捨5入でも良いのでしょうね。
今回のデータでは「−方向の誤差(.9999・・・)」に気付いたのですが、
データによっては「+方向の誤差(.0001・・・)」が出る時も有るのでしょうね。
色々と有り難うございました。
([HomePage]を見ました、たいへん分かりやすく、勉強になります。)
ツイート | ![]() |