質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Q&A

解決済

2回答

1668閲覧

半径が非常に大きいときに整数の格子点から円周率を近似する

grape_ll

総合スコア83

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

0グッド

0クリップ

投稿2020/06/01 13:36

質問内容

タイトルの通りにはなるのですが,半径が最大で1億(100000000)の円が内部に含む格子点の数から円周率を近似するときに半径が10000まではしっかり出来ているのですが100000になると-214294.212864207070000というようにあり得ない数値が出てしまいます.なぜこのような負の数が出てしまうのかということと,計算時間が短縮するための工夫を教えていただきたいです.よろしくお願いいたします.

コード

C

1#include<stdio.h> 2#include<math.h> 3double count(int m){ 4 long long check=0; 5 double answer; 6 for(int i=1;i<=m;i++){ 7 check+=(int)sqrt(m*m-i*i); 8 } 9 answer=((double)(check*4+m*4+1)/(double)(m*m)); 10 return answer; 11} 12int main(void){ 13 int n; 14 scanf("%d",&n); 15 printf("%d:%.15f\n",n,count(n)); 16 return 0; 17}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

100000になると-214294.212864207070000というようにあり得ない数値が出てしまいます.

m*mintで計算できる範囲を超えている、ということかと思います。

投稿2020/06/01 13:42

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

grape_ll

2020/06/01 13:56

ご指摘いただいた通り,intの範囲を超えていたみたいでlong longにしてみたのですが,100000000ではマイナスにならないのに50000,1000000ではマイナスになるといったことが起きてしまいました.これはより大きい数字で出来ているのでlong long で足りないなどの話では解決できなさそうと考えたのですが,対処法などはありますでしょうか. また本来半径が大きくなれば円周率の精度もよくなるはずなのですが,100000では精度が落ちていました.このことについてもぜひ教えていただければと思います. コードは以下のようにしました. #include<stdio.h> #include<math.h> double count(int m){ long long check=0; double answer; for(int i=1;i<=m;i++){ check+=(long long)sqrt(m*m-i*i); } answer=((double)(check*4+m*4+1)/(double)(m*m)); return answer; } int main(void){ int n; scanf("%d",&n); printf("%d:%.15f\n",n,count(n)); return 0; }
maisumakun

2020/06/01 13:57

> long longにしてみたのですが なっていません。依然としてm*mはintで計算されます。
maisumakun

2020/06/01 13:58

(引数のmもlong longで受け取るようにしてしまうのが、手抜きですがいちばん確実です)
grape_ll

2020/06/01 14:06

#include<stdio.h> #include<math.h> double count(long long m){ long long check=0; double answer; for(int i=1;i<=m;i++){ check+=(long long)sqrt(m*m-i*i); } answer=((double)(check*4+m*4+1)/(double)(m*m)); return answer; } int main(void){ long long n; scanf("%lld",&n); printf("%lld:%.15f\n",n,count(n)); return 0; } このようなコードにしてみたのですが.1000000あたりから精度が悪くなり4.0付近になってしま運みたいなのですが,どうすればよいでしょうか.よろしくお願いいたします.
maisumakun

2020/06/01 14:08

iがintなので、i*iがオーバーフローしています。これもlong longにするか、(long long)i*iのようにしてintでの乗算を回避してください。
grape_ll

2020/06/01 14:09

46000を超えたあたりから精度が悪くなっているようです PS C:\Users\rokok\pro\proc\01> ./try 35000:3.141592360000000 40000 40000:3.141592205625000 45000 45000:3.141592322469136 50000 50000:3.459391803600000 47500 PS C:\Users\rokok\pro\proc\01> ./try 47500 47500:3.262891079002770 PS C:\Users\rokok\pro\proc\01> ./try 47000 47000:3.213940438660027 PS C:\Users\rokok\pro\proc\01> ./try 46000 46000:3.141592223534972 PS C:\Users\rokok\pro\proc\01> ./try 46500 46500:3.160249821713493
grape_ll

2020/06/01 14:16

ご指摘いただいた通り,iについてもlong long にしたところ計算はうまくいったように思われます. ありがとうございます. 計算時間も問題ないみたいです. ただ,1億のときの精度が少し足りないようなのですが工夫するところはありますでしょうか.よろしくお願いいたします. 自分 100000000:3.141592653586803 例 100000000:3.141592653586796 #include<stdio.h> #include<math.h> double count(long long m){ long long check=0; double answer; for(long long i=1;i<=m;i++){ check+=(long long)sqrt(m*m-i*i); } answer=((double)(check*4+m*4+1)/(double)(m*m)); return answer; } int main(void){ long long n; scanf("%lld",&n); printf("%lld:%.15f\n",n,count(n)); return 0; }
guest

0

m * m - i * i」とか「m * m」とか、int同士の掛け算をしているところがありますね。
おそらくお使いの処理系ではintが32ビット長で、符号付きなので±21億ちょっとまでしか扱えません。
100000 * 100000で100億になるので、範囲を超えてしまっていおり、正しい値になりません。
なぜ負の値になるのかは、「2の補数」で検索してみてください。

投稿2020/06/01 13:52

Daregada

総合スコア11990

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

grape_ll

2020/06/01 14:10 編集

おっしゃる通り,intでは足りないようでしたのでlong long でやらせていただいたのですが,100000000ではマイナスにならないのに50000,1000000ではマイナスになるといったことが起きてしまいました.これはより大きい数字で出来ているのでlong long で足りないなどの話では解決できなさそうと考えたのですが,対処法などはありますでしょうか. また本来半径が大きくなれば円周率の精度もよくなるはずなのですが,100000では精度が落ちていました.このことについてもぜひ教えていただければと思います. コードは以下のようにしました. #include<stdio.h> #include<math.h> double count(long long m){ long long check=0; double answer; for(int i=1;i<=m;i++){ check+=(long long)sqrt(m*m-i*i); } answer=((double)(check*4+m*4+1)/(double)(m*m)); return answer; } int main(void){ long long n; scanf("%lld",&n); printf("%lld:%.15f\n",n,count(n)); return 0; }
Daregada

2020/06/01 14:08

キャストの使い方を確認してみてください。sqrtの「返り値」を long long int にキャストしていますが(これはやらなくても暗黙の型変換で long long int になります)、やらなくてはいけないのは、「掛け算をする前に m を long long int にキャストする」ことです。
grape_ll

2020/06/01 14:11

他の方にもご指摘いただいたので訂正させていただきました. 勉強不足で申し訳ございません. お手数かとは思いますがご確認お願い致します。 #include<stdio.h> #include<math.h> double count(long long m){ long long check=0; double answer; for(int i=1;i<=m;i++){ check+=(long long)sqrt(m*m-i*i); } answer=((double)(check*4+m*4+1)/(double)(m*m)); return answer; } int main(void){ long long n; scanf("%lld",&n); printf("%lld:%.15f\n",n,count(n)); return 0; }
Daregada

2020/06/01 14:30

いやなんで確認まですることになってるのさ。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問