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

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

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

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

Q&A

解決済

2回答

1151閲覧

平方根の計算 入力 出力

ta-9

総合スコア11

C

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

0グッド

0クリップ

投稿2020/04/25 02:20

実現したいこと

非負整数 n ( 0 ≦ n < 2^63 )を読み取り、n の整数平方根(√nを超えない最大の整数)を計算し、1行出力するプログラムの作成。

###前提
与えられる整数値は、0 または正であり、2^63 未満。

###質問したいこと
2の平方根は下記のように作ってみましたが今回の範囲n ( 0 ≦ n < 2^63 )はどうすれば良いか教えて頂きたいです。

c

1#include <stdio.h> 2#include <math.h> 3 4int main(void) 5{ 6 double x = 2.0; 7 double y = 0; 8 // xの平方根を計算 9 y = sqrt(x); 10 // 計算結果の表示 11 printf("%f", y); 12 13 return 0; 14}

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

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

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

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

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

y_waiwai

2020/04/25 02:24

今のコードではどういう不具合があるんでしょうか
guest

回答2

0

ベストアンサー

100000000(1億)の2乗は、10000000000000000(1京)。
したがって、(1京 - 1) の 9999999999999999 の平方根は 100000000より小さく、
整数平方根は 99999999 のはず。
ところが、sqrt(9999999999999999) は 100000000 になってしまいます。

なぜかというと次のコードを実行すると分かります。

C

1#include <stdio.h> 2 3int main(void) 4{ 5 for (long long n = 9999999999999995; n <= 10000000000000005; n++) { 6 double d = n; 7 printf("%17lld, %llx, %.13a, %19.1f\n", n, n, d, d); 8 } 9}

実行結果

9999999999999995, 2386f26fc0fffb, 0x1.1c37937e07ffep+53, 9999999999999996.0 9999999999999996, 2386f26fc0fffc, 0x1.1c37937e07ffep+53, 9999999999999996.0 9999999999999997, 2386f26fc0fffd, 0x1.1c37937e07ffep+53, 9999999999999996.0 9999999999999998, 2386f26fc0fffe, 0x1.1c37937e07fffp+53, 9999999999999998.0 9999999999999999, 2386f26fc0ffff, 0x1.1c37937e08000p+53, 10000000000000000.0 10000000000000000, 2386f26fc10000, 0x1.1c37937e08000p+53, 10000000000000000.0 10000000000000001, 2386f26fc10001, 0x1.1c37937e08000p+53, 10000000000000000.0 10000000000000002, 2386f26fc10002, 0x1.1c37937e08001p+53, 10000000000000002.0 10000000000000003, 2386f26fc10003, 0x1.1c37937e08002p+53, 10000000000000004.0 10000000000000004, 2386f26fc10004, 0x1.1c37937e08002p+53, 10000000000000004.0 10000000000000005, 2386f26fc10005, 0x1.1c37937e08002p+53, 10000000000000004.0

long long は 63ビットの精度があります。10000000000000000 は 54ビットです。
double は 53ビットの精度しかありません。
9999999999999999~10000000000000001 の 3つの値が 10000000000000000.0 という
一つの値になってしまいます。
9999999999999999の平方根を double の sqrt で求められないのはこのためです。

投稿2020/04/25 04:55

編集2020/04/25 04:58
kazuma-s

総合スコア8224

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

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

ta-9

2020/04/26 05:30

ご回答有難うございます。 ベストアンサーにさせて頂きます。
guest

0

同じ質問をYahoo知恵袋で見ました。質問者は「回答だけを知りたいわけじゃない」とか言ってましたけど、回答が得られたら質問削除して消えましたね。同じ問題なので、きっとあなたの周りの誰かなんでしょう。

で。

今回の範囲n ( 0 ≦ n < 2^63 )はどうすれば良いか教えて頂きたいです。

「範囲をどうすればよいか」というのはちょっと解釈が難しいです。どういう意味でしょうか。

もし、「範囲のチェックはどうしたらよいのか」という話であれば、
あなたが質問に書いているように与えられる値の「前提」なのですからチェックは必要ではありません。

「その範囲の値を正しく扱うためにはどうしたらよいのか」という話であれば...
まず、今の方針ではダメだ、ということを確認して下さい。これでどんな結果が得られますか?

C

1#include <math.h> 2#include <stdio.h> 3 4int main(void) { 5//2147483647即ち0x7fffffff<2^31なのでこの2乗は2^63より小さいので、 6//2147483647*2147483647を与えたら解は2147483647になるはず 7 double x = 2147483647ull * 2147483647ull - 1;//1を引いたので、解は2147483646にならなきゃいけない 8 double y = 0; 9 // xの平方根を計算 10 y = sqrt(x); 11 // 計算結果の表示 12 printf("%f", y);//いくつになりましたか? 13 14 return 0; 15}

なにはともあれ2^63以下の整数をちゃんと扱えるunsigned long long型を使う必要があるでしょう。コンパイラによってはその時点で「ダメ」かも知れません。(つまり、どんなCコンパイラでも出来なきゃいけない、という問題であれば「不可能」で終わりにすればいいです)
また、sqrtみたいな便利な関数はないので、実際にある数の2乗を計算して、与えられた数と比較して「与えられた数を超えない最大の'ある数'」を探していくことになると思います。

他の方からもっといい方法がでてくるかも知れませんが、

投稿2020/04/25 04:34

thkana

総合スコア7703

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問