掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.28439

符号付小数点19バイトの数値の計算
投稿者---真島(2006/10/12 22:38:40)


符号付小数点19バイトの数値の計算でなやんでおります。
文字列としてで受け取った"+000001234567890.11"などの数値を計算したいのですが、下記のようにするとまったくうまくいきません。
この場合、どのような型、関数を使用するとうまくいくのでしょう?
環境は、XP、VC++ExpressEditionです。

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int main(int argc, char* argv[])
{
double num,num2;
char str[]="+600000000100000.21";
char str2[]="+600000000100000.21";

num=atof(str);
num2=atof(str2);
printf("%lf + %lf = \n");
printf("%lf\n",num+num2);


return 0;
}


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:符号付小数点19バイトの数値の計算 28440 nano 2006/10/12 22:52:17
<子記事> Re:符号付小数点19バイトの数値の計算 28441 yoh2 2006/10/12 23:03:09
<子記事> Re:符号付小数点19バイトの数値の計算 28469 Hermit 2006/10/13 20:44:24


No.28440

Re:符号付小数点19バイトの数値の計算
投稿者---nano(2006/10/12 22:52:17)


>下記のようにするとまったくうまくいきません。

どううまくいかないか、具体的に書いてください。
どういう結果を得るべきところ、どうなってしまうので
「うまくいかない」と判断されているのでしょうか。


この投稿にコメントする

削除パスワード

No.28444

Re:符号付小数点19バイトの数値の計算
投稿者---真島(2006/10/12 23:34:41)


>どううまくいかないか、具体的に書いてください。

失礼いたしました。
下のyoh2さんのご指摘で、ちょっと直して、strtodも使ってみたのですが、
結果
600000000100000.250000 + 600000000100000.250000 =
1200000000200000.500000
600000000100000.250000 + 600000000100000.250000 =
1200000000200000.500000
このようになってしまいます。
渡している文字列は、最終桁が1のはずなのにatof、strtodともに5に変わってしまっているのです。
(演算自体は、大丈夫なようですが。)
ちなみに修正したソースです。

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int _tmain(int argc, char* argv[])
{
double num,num2;
char str[]="+600000000100000.21";
char str2[]="+600000000100000.21";
char *e;

num=atof(str);
num2=atof(str2);
printf("%lf + %lf = \n",num,num2);
printf("%lf\n",num+num2);

num=strtod(str,&e);
num2=strtod(str2,&e);
printf("%lf + %lf = \n",num,num2);
printf("%lf\n",num+num2);


return 0;
}


この投稿にコメントする

削除パスワード

No.28441

Re:符号付小数点19バイトの数値の計算
投稿者---yoh2(2006/10/12 23:03:09)


どううまくいかないのでしょう?

- コンパイルできない?
- リンクできない?
- 実行時に落ちる?
- 実行できて正常終了するけど、期待と違う動作をする?

>    printf("%lf + %lf = \n");

で、%lfに対応する引数がないから変になっているとか?
なお、ここを
     printf("%lf + %lf = \n", num, num2);

と直して実行した場合、

600000000100000.250000 + 600000000100000.250000 =
1200000000200000.500000

と出力されました。

ちなみに、文字列→dobule変換関数には、atof()の他にstrtod()というものもあります。


この投稿にコメントする

削除パスワード

No.28442

Re:符号付小数点19バイトの数値の計算
投稿者---真島(2006/10/12 23:19:27)


レスありがとうございます。
>lfに対応する引数がないから変になっているとか?
もうしわけありません。少なくともここはおかしかったですね。
おっしゃるとおり引数を加えて実行しています。

>600000000100000.250000 + 600000000100000.250000 =
>1200000000200000.500000

同じく私もこのように出力されます。
この最後の桁が1のはずが、5になってしまうのがなぜなのか、また、それの対処法をお教えいただきたいという状況です。

#strtod()というのは初耳ですので、まずは試してみたいと思います。




この投稿にコメントする

削除パスワード

No.28445

Re:符号付小数点19バイトの数値の計算
投稿者---nano(2006/10/12 23:36:03)


>この最後の桁が1のはずが、5になってしまうのがなぜなのか、また、それの対処法をお教えいただきたいという状況です。

浮動小数点数の計算を行なう際、いくらかの誤差が出るのは
やむを得ないと思います。


この投稿にコメントする

削除パスワード

No.28446

Re:符号付小数点19バイトの数値の計算
投稿者---yoh2(2006/10/12 23:56:45)


>>600000000100000.250000 + 600000000100000.250000 =
>>1200000000200000.500000
>
>同じく私もこのように出力されます。
>この最後の桁が1のはずが、5になってしまうのがなぜなのか、また、それの対処法をお教えいただきたいという状況です。

すっかり見落としてました。確かに末尾が変ですね。
これはdoubleの精度の限界です。
<float.h>をincludeすると定義されるマクロDBL_DIGの値が、doubleで保証できる
値の精度となります。

# あれ? float.hって、C89の時からあったっけ?


VC++2005ではDBL_MAXが15ですので、17桁目になる末尾の1は格納しきれません。
実は16桁目の2もすでに怪しいです。
ではlong doubleにしたらどうかというと、LDBL_DIGも同じく15です。
組込み型を使う以上、これ以上はどうしようもなさそうです。

まあ、少し探せば、有効桁を変えられる数値計算ライブラリが見付かったりしますので、
どうしても高い精度が必要であれば、そういったライブラリを探して使うのも手です。


この投稿にコメントする

削除パスワード

No.28447

Re:符号付小数点19バイトの数値の計算
投稿者---真島(2006/10/13 00:20:11)


nanoさんyoh2さんありがとうございます。

精度の限界を超えていたわけですね。
こういった場合は、一般的にはどうするものでしょう?(諦めない場合)

>まあ、少し探せば、有効桁を変えられる数値計算ライブラリが見付かった>りしますので、
>どうしても高い精度が必要であれば、そういったライブラリを探して使う>のも手です。

これは、標準関数ではなく、誰かが作った関数を探して利用しようということですか?
それとも、対応できるコンパイラや環境を探そうということでしょうか?

また、もし自身で関数を作って対応するという場合は、
文字の配列として一桁づつ計算して、配列として、答えを組み立てるロジックになるんでしょうか?


この投稿にコメントする

削除パスワード

No.28448

Re:符号付小数点19バイトの数値の計算
投稿者---yoh2(2006/10/13 01:28:08)


>>まあ、少し探せば、有効桁を変えられる数値計算ライブラリが見付かった>りしますので、
>>どうしても高い精度が必要であれば、そういったライブラリを探して使う>のも手です。
>
>これは、標準関数ではなく、誰かが作った関数を探して利用しようということですか?
>それとも、対応できるコンパイラや環境を探そうということでしょうか?

前者を意識して書きました。適切なライブラリを探して利用するのが、

>こういった場合は、一般的にはどうするものでしょう?(諦めない場合)

に対する答えになります。
不勉強にてライブラリの具体例を挙げることはできませんが。
UNIXやMac OS Xなら、gmpというライブラリがあるのですが、どうもWindowsネイティブで
動かせるようには作られてない模様。

また、状況が許すなら後者でもよいのですが、同じPC上で動く限り、ハードウェアに縛られて、
コンパイラを変えても限界はあまり変わらないと思います。
x86のFPUでは、18〜19桁あたりが限界だったはずです。


>また、もし自身で関数を作って対応するという場合は、
>文字の配列として一桁づつ計算して、配列として、答えを組み立てるロジックになるんでしょうか?

いろいろな方法があります。
が、結論を先に述べると、自力での実装は労力の無駄だと思います。
C言語の知識の他、数値計算に精通していないとまず実装できません(四則演算の除算とか)し、
理論を知っていたとしても、かなり面倒な作業であることには変わりありません。
数値計算を専門に行う(数値計算を利用して何かを行うの*ではなく*、数値計算の手法
そのものを専門に研究する)のでないかぎり、手間と見返りの差が大きいと思います。

-- 以下は蛇足。--
自力実装をする場合、真島さんの書かれた方法もひとつの手ですが、例えば、同じアプローチで、
一桁をunsiged intにしてしまう(unsigned intが32ビットなら、4294967296進数!)
とするとメモリ消費量も計算速度も向上するかもしれません。
なお、これらの方法は、絶対値が極端に大きな数や0に極近い数で必要な有効桁を確保するには、
大量のメモリを消費してしまいます。
例えば、最上位の位が10の200乗の数を扱う場合、有効桁が20桁で十分な場合でも、
200桁分の領域を確保する必要がありますし、もちろん計算も200桁分の行わなければ
なりません。最上位の位が10の-200乗の場合も同様(どころか、さらに少しタチが悪い)です。

他のアプローチとして、FPUで行っているような計算をシミュレートする方法もあります。
この場合、一つの数値は符号、指数部、仮数部に分けて管理することになり、有効桁数は
仮数部のサイズによります。


この投稿にコメントする

削除パスワード

No.28480

Re:符号付小数点19バイトの数値の計算
投稿者---yoh2(2006/10/14 19:59:03)


>UNIXやMac OS Xなら、gmpというライブラリがあるのですが、どうもWindowsネイティブで
>動かせるようには作られてない模様。

やや手順はややこしいですが、Windowsネイティブでgmpを使えるようです。
http://forums.belution.com/ja/cpp/000/018/88s.shtml
VC++ 2005 Expressで試して、gmpをWindowsから利用できることも確認しました。


この投稿にコメントする

削除パスワード

No.28469

Re:符号付小数点19バイトの数値の計算
投稿者---Hermit(2006/10/13 20:44:24)


long double のある、bcc32 などだったら出来そうですが、
VC++ は、無いか、有っても、double と同精度だったかな・・・

gcc の version 3.? あたりは、有るらしい話も聞いているけど・・よく知らない。



この投稿にコメントする

削除パスワード

No.28470

Re:符号付小数点19バイトの数値の計算
投稿者---真島(2006/10/14 00:15:33)


>long double のある、bcc32 などだったら出来そうですが、

Hermitさんありがとうございます。
VCでもlong doubleが使えるようなのですが、だめでした。
bcc32というのも試してみようかなと思っているのですが、
WINAPIだともしかしたらできますかね?
うまいことVCのCから呼び出せそうな気がしたんですが・・


この投稿にコメントする

削除パスワード

No.28471

Re:符号付小数点19バイトの数値の計算
投稿者---Hermit(2006/10/14 08:13:07)


>WINAPIだともしかしたらできますかね?
WIN32API は良く知らないので絶対とは言いませんが、
VC++ が、10byte 浮動小数点演算を持っていないようなので、
無理ではないでしょうか。

Borland C++ 5.5.1 で、以下のソースでは、
double(8byte浮動小数演算)で、精度を保てませんので、
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
  long double num,num2;
  double num3;
  char str[]="+600000000100000.21";
  char str2[]="+600000000100000.21";
  sscanf(str,"%Lf",&num);
  sscanf(str2,"%Lf",&num2);
  printf("%Lf + %Lf = \n",num,num2);
  printf("%Lf\n",num+num2);
  num3 = num;
  printf("%Lf\n",(long double)num3);
  return 0;
}


で、
600000000100000.210000 + 600000000100000.210000 =
1200000000200000.420000
600000000100000.250000 <- double では無理なのかな。



この投稿にコメントする

削除パスワード

No.28473

Re:符号付小数点19バイトの数値の計算
投稿者---yoh2(2006/10/14 15:09:04)


参考までに、x86のFPU(俗にx87と呼ばれます)が扱える浮動小数点数の精度について。
x87では、浮動小数点数にIEEE 754形式を採用しています。
「IEEE 754 浮動小数点」あたりで検索するとごろごろ出てきますので、詳細はそちらを参照して下さい。

簡単に書くと、IEEE 754形式とは、浮動小数点数を
±1.xxxxxx × 2**y ("**"はべき乗)
と表す形式で、保持できる桁数は、xxxxxxの部分(仮数部と呼びます)の精度によります。

x87で扱える浮動小数点数は3種類あり、それぞれのサイズは以下のようになっています。
全体サイズ          仮数部(10進精度)
32ビット(単精度)    24ビット(7桁)
64ビット(倍精度)    53ビット(15桁)
80ビット(拡張精度)  64ビット(18桁)

なので、そもそも拡張精度を扱えないVC++ 2005 (設定オプションを見落しているだけかも) は
15桁、拡張精度が扱えるBorland C++ 5.5.1でも18桁が限界です。
前にちらっと書いた、精度がハードウェアに縛られるというのはこういった意味です。
まあ、18桁で十分ならコンパイラ乗り換えがお手軽です。

これ以上の精度を望むなら、ソフトウェア計算に頼らなくてはなりません。
WINAPIにそういったものがあるかどうかは分かりませんが。

コンパイラによっては、double等の計算をFPUに頼らないソフトウェア計算に展開できる
ものもありますが、大抵の場合、その目的は、FPUを持たない計算機でFPUを用いた場合と同等の
計算結果を得られるようにするためのもので、より高精度の計算ができるようなものでは
ありません。

ちなみにx86用gcc-4.1.1では、浮動小数点演算をソフトウェアで行うというオプションと、
long doubleを128ビットにするというオプションがあるのですが、この二つを組み合わせても、
精度は80ビット浮動小数点数と変わりありませんでした。

さらに蛇足ですが、ハードウェアが変わると精度が変わる例として、PowerPC用gcc-4.1.1では、
128ビット浮動小数点数(仮数部106ビット; 31桁)の数を扱えたりします。


この投稿にコメントする

削除パスワード

No.28474

Re:符号付小数点19バイトの数値の計算
投稿者---yoh2(2006/10/14 15:14:09)


訂正。
> 32ビット(単精度)    24ビット(7桁)
7桁ではなく、6桁です。


この投稿にコメントする

削除パスワード

No.28475

Re:符号付小数点19バイトの数値の計算
投稿者---yoh2(2006/10/14 15:26:35)


>さらに蛇足ですが、ハードウェアが変わると精度が変わる例として、PowerPC用gcc-4.1.1では、
>128ビット浮動小数点数(仮数部106ビット; 31桁)の数を扱えたりします。

よく見たら、128ビット浮動小数点数はFPUとソフトウェア計算を組み合わせて実現している気配が……


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧