2個の変数の値を入れ替えるには

解決


Taku  2001-12-10 18:10:06  No: 348

同じ型の変数(var A,B:single)が有るとして
その値を入れ替える関数が有ったと思うのですが
どなたか教えて下さい。
A:=123.456;
B:=789.123;
関数(A,B); <--?
A=789.123
B=123.456

又、以前はsingle型に整数を代入すると小数点が勝手に付いた
と思うのですが、Delphi6ではそのまま保持しているようです
この違いについてご存知の方、お願いします。


にしの  2001-12-10 19:22:13  No: 349

2つの値を交換する関数があるかどうかは確認できませんでした。
VBだとSwapだったと思うのですが、DelphiのSwapは上位バイトと下位バイトを交換するだけでした。
この関数の場合、ロジックは簡単なので、1つユニットを作って、そこにSwapFloatなどとして作れば回避できますがどうでしょう。
僕は、見つからない関数などを別ユニットで作っておいて、見つけたときにその関数を交換するようにしています。

> 又、以前はsingle型に整数を代入すると小数点が勝手に付いた
> と思うのですが、Delphi6ではそのまま保持しているようです
そのまま保持というのは、どういう現象でしょうか。
つまり、
var
  a: single;
begin
  a := 12345;
  b := @a;
  Edit1.Text := intToHex(integer(b[0]), 2)
                + intToHex(integer(b[1]), 2)
                + intToHex(integer(b[2]), 2)
                + intToHex(integer(b[3]), 2);
とすると、Edit1(TEditコンポーネント)に、
39300000
と表示されるということでしょうか。
# 12345の16進数は、$00003039
Delphi5では、きちんとSingle型で代入できています。
# 00E44046と表示されました

それとも、Format('%f', a);としたときに、12345.00と表示されることでしょうか。
Delphi5では、'%f'のときは12345.00と表示されます。'%.0f'なら、12345と表示されます。
Delphi6では、省略したときに表示する桁数を変更したのかもしれません。


Taku  2001-12-11 06:27:32  No: 350

にしの  さま
ありがとうございました
2つの値を交換する関数は、以前使ったような気がしたのですが
勘違いかもしれません。

Single型の件は質問を変更します
var n,m:single;
begin
     n:=1.1;
     m:=1.1;
     edit1.Text:=floattostr(n+m);
end;
結果、2.20000004768372  となります。
0.00000004768372の誤差は、どこから来るのでしょうか?
ループ計算した場合には誤差が拡大すると思いますので
正しい計算をする方法は無いのでしょうか?
又、double型にすると上記桁数では、正確に表示されます
同じように最小桁で誤差が生じているのでしょうか?


にしの  2001-12-11 07:01:32  No: 351

この場合、floattostr(n)でも、1.1にはなりませんよね。
# うちの環境では1.10000002384186とでました

有効桁数が違うため、singleでは誤差がつき、doubleではつきません。
FloatToStr関数は、15桁の有効桁数で変換しています。
double型の有効桁数は、15〜16、一方、single型の有効桁数は7〜8。

もし気になるのでしたら、FloatToStrF関数で、フォーマットを指定して変換するとよいです。


にしの  2001-12-11 07:09:02  No: 352

> ループ計算した場合
ためしにしてみました。

procedure TForm1.Button2Click(Sender: TObject);
var
  a,b: single;
  n,m:single;
  i, j : integer;
begin
  n:=0;
  m := 1.1;
  a := 0;
  b := 11;

  for i := 0 to 999 do
  begin
    for j := 0 to 999 do
    begin
      n := n + m;
      a := a + b;
    end;
  end;
  Edit1.Text := FloatToStr(n);
  Edit2.Text := FloatToStr(a);
end;
です。singleとdouble、両方試しました。
結果は、
singleの場合、
1.1を1000000回  1110920.5
11を1000000回  11000000

doubleの場合、
1.1を1000000回  1099999.99998869
11を1000000回  11000000

doubleでも誤差は生じます。
これは、内部で少数を2進数で持っているからだと思います。
もし、精度を上げたければ、100倍なり1000倍なりして、整数にしてから計算させたほうがよいです。
速度も速くなりますし。


Taku  2001-12-11 07:57:30  No: 353

にしの  さま
解りやすい回答ありがとうございます
これは以前から気になっていたのですが
実際に三角関数の計算で頻繁に使用している
pi(3.1415926535897932385)の問題です。
例えば円周すれすれで接する交点を計算したときに
誤差により外れる場合があると思います。
piを整数にするにはLongword型でも収まらないので...
完全な計算は、やはり無理なのでしょうか?


にしの  2001-12-11 08:28:13  No: 354

桁落ちですか。
そういう場合は、ある程度精度を犠牲にして、=0などの、「点」を調べるための計算を、<0+n、>0−nなどの、範囲を調べる計算に変えるとうまくいくと思います。

また、計算方法を数学での公式でなく、くずした形で計算すると誤差が少なくなることがあります。
>参考文献「C言語による最新アルゴリズム事典」技術評論社  奥村晴彦著


Taku  2001-12-11 18:39:24  No: 355

大変参考になりました
有難うございました。


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加