teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

5

削除

2020/08/21 21:17

投稿

mjk
mjk

スコア303

answer CHANGED
@@ -1,95 +1,1 @@
1
- > nの大きさとしては10万以下を想定しているのですが
2
- > n = 26033 までは正常に動作するのですが
3
-
4
- ##**そもそも**
5
- C++で扱える整数型の最大値を21!の時点で超えているはずです。
6
- %MODの計算をする以前に21!を計算した時点で桁あふれによって変数の値がおかしくなっているはずです。
7
- unsigned long long 型変数の最大値を使ったとしても20!までしか正確な計算は出来ないはずです。
8
-
9
- 20桁を超える計算をするには多桁計算を実装したりBOOSTの多倍長整数を利用するなどが必要かと思います。
10
-
11
- `constexpr unsigned long long INF = std::numeric_limits<unsigned long long>::max();`
12
- unsigned long long 型変数の最大値(20桁) = 18,446,744,073,709,551,615
13
-
14
- ##Win10の関数電卓で計算
15
- 20!では超えていませんが、21!でunsigned long long 型変数の最大値を超えてしまっています。
16
- ![](909402925e328c023d681398db1c05ef.jpeg)
17
-
18
- ##n!出力して20!と21!を確認するサンプル
19
- ![イメージ説明](aac179b55299882850c6c330c9e50384.jpeg)
20
- INF-n!が減り続けるはずなのに21!以降の結果を見ると増えたり減ったりしている。
21
- 21!以降では桁あふれによってn!の値が正確でないことが確認出来る。
22
-
23
- ```C++
24
- #include <bits/stdc++.h>
25
- std::vector<unsigned long long> v;
26
- constexpr unsigned long long INF = std::numeric_limits<unsigned long long>::max();
27
-
28
- int main() {
29
- std::cin.tie(0);
30
- std::ios::sync_with_stdio(false);
31
-
32
- unsigned long long N;
33
- std::cin >> N;
34
- v.resize(N + 1, 0);
35
-
36
- v[0] = 1;
37
- for (unsigned long long i = 1; i <= N; ++i) {
38
- v[i] = v[i - 1] * i;
39
- }
40
-
41
- for (unsigned long long i = 0; i <= N; ++i) {
42
-
43
- std::cout << std::setfill('0') << std::right << std::setw(2) << i;
44
- std::cout << " : INF:" << INF << " -i!:";
45
- std::cout << std::setfill('0') << std::right << std::setw(20) << v[i] << " ";
46
- std::cout << std::setfill('0') << std::right << std::setw(20) << INF - v[i];
47
-
48
- if (i == 20 or i == 21) {
49
- std::cout << "***";
50
- }
51
- std::cout << std::endl;
52
- }
53
-
54
- getchar();
55
- return 0;
56
- }
57
- ```
58
-
59
- ##本題の再帰処理テスト
60
- 自環境で階乗計算のみ再帰計算させて確認したところ、`n=32503` 以降で例外エラーとなりました。
61
- 途中から桁あふれてるので計算結果は全て0となっています。
62
- 仮に桁あふれを考慮して正確な計算をしたとしても再帰処理が深くなりすぎると処理が継続出来なくなるということです。
63
-
64
- > 再帰呼び出しを繰り返していくとスタックを消費しますので、再帰できる回数には限度があります。
65
- maisumakunさんがすでに回答されているとおりです。
66
-
67
- `例外発生しました`
1
+ ご指摘ありまたの回答を削除しました
68
- `Segmentation fault`
69
- 実行環境やコンパイル環境で多少の差は出ると思います。
70
- ![イメージ説明](3d7f107ed3c4f48f4ac78a4c2de73dc0.jpeg)
71
-
72
- ```C++
73
- #include <bits/stdc++.h>
74
-
75
- const long long MOD = 1E+09 + 7;
76
- long long f(const long long &n) {
77
- if (n == 0) {
78
- return 1;
79
- }
80
- return f(n - 1) * n;
81
- }
82
-
83
- int main() {
84
- std::cin.tie(0);
85
- std::ios::sync_with_stdio(false);
86
-
87
- long long n = 100000;
88
- for (long long i = 0; i <= n; i++) {
89
- std::cout << "(" << i << "!) % " << MOD << " = " << f(i) % MOD << std::endl;
90
- }
91
-
92
- getchar();
93
- return 0;
94
- }
95
- ```

4

追記 再帰処理のテスト

2020/08/21 21:16

投稿

mjk
mjk

スコア303

answer CHANGED
@@ -57,8 +57,13 @@
57
57
  ```
58
58
 
59
59
  ##本題の再帰処理テスト
60
- 自環境で階乗計算のみ再帰計算させて確認したところ、`n=32503` 以降で例外エラーとなりました。
60
+ 自環境で階乗計算のみ再帰計算させて確認したところ、`n=32503` 以降で例外エラーとなりました。
61
+ 途中から桁あふれてるので計算結果は全て0となっています。
62
+ 仮に桁あふれを考慮して正確な計算をしたとしても再帰処理が深くなりすぎると処理が継続出来なくなるということです。
61
63
 
64
+ > 再帰呼び出しを繰り返していくとスタックを消費しますので、再帰できる回数には限度があります。
65
+ maisumakunさんがすでに回答されているとおりです。
66
+
62
67
  `例外が発生しました`
63
68
  `Segmentation fault`
64
69
  実行環境やコンパイル環境で多少の差は出ると思います。

3

追記 再帰処理のテスト

2020/08/21 20:36

投稿

mjk
mjk

スコア303

answer CHANGED
@@ -54,4 +54,37 @@
54
54
  getchar();
55
55
  return 0;
56
56
  }
57
+ ```
58
+
59
+ ##本題の再帰処理テスト
60
+ 自環境で階乗計算のみ再帰計算させるて確認したところ、`n=32503` 以降で例外エラーとなりました。
61
+
62
+ `例外が発生しました`
63
+ `Segmentation fault`
64
+ 実行環境やコンパイル環境で多少の差は出ると思います。
65
+ ![イメージ説明](3d7f107ed3c4f48f4ac78a4c2de73dc0.jpeg)
66
+
67
+ ```C++
68
+ #include <bits/stdc++.h>
69
+
70
+ const long long MOD = 1E+09 + 7;
71
+ long long f(const long long &n) {
72
+ if (n == 0) {
73
+ return 1;
74
+ }
75
+ return f(n - 1) * n;
76
+ }
77
+
78
+ int main() {
79
+ std::cin.tie(0);
80
+ std::ios::sync_with_stdio(false);
81
+
82
+ long long n = 100000;
83
+ for (long long i = 0; i <= n; i++) {
84
+ std::cout << "(" << i << "!) % " << MOD << " = " << f(i) % MOD << std::endl;
85
+ }
86
+
87
+ getchar();
88
+ return 0;
89
+ }
57
90
  ```

2

0!=1修正の画像差し替え

2020/08/21 20:30

投稿

mjk
mjk

スコア303

answer CHANGED
@@ -16,7 +16,7 @@
16
16
  ![](909402925e328c023d681398db1c05ef.jpeg)
17
17
 
18
18
  ##n!出力して20!と21!を確認するサンプル
19
- ![イメージ説明](a16f6733061b7a69f9fc6daa92a62943.jpeg)
19
+ ![イメージ説明](aac179b55299882850c6c330c9e50384.jpeg)
20
20
  INF-n!が減り続けるはずなのに21!以降の結果を見ると増えたり減ったりしている。
21
21
  21!以降では桁あふれによってn!の値が正確でないことが確認出来る。
22
22
 

1

0!=1を修正

2020/08/21 19:37

投稿

mjk
mjk

スコア303

answer CHANGED
@@ -17,6 +17,8 @@
17
17
 
18
18
  ##n!出力して20!と21!を確認するサンプル
19
19
  ![イメージ説明](a16f6733061b7a69f9fc6daa92a62943.jpeg)
20
+ INF-n!が減り続けるはずなのに21!以降の結果を見ると増えたり減ったりしている。
21
+ 21!以降では桁あふれによってn!の値が正確でないことが確認出来る。
20
22
 
21
23
  ```C++
22
24
  #include <bits/stdc++.h>
@@ -31,8 +33,8 @@
31
33
  std::cin >> N;
32
34
  v.resize(N + 1, 0);
33
35
 
34
- v[1] = 1;
36
+ v[0] = 1;
35
- for (unsigned long long i = 2; i <= N; ++i) {
37
+ for (unsigned long long i = 1; i <= N; ++i) {
36
38
  v[i] = v[i - 1] * i;
37
39
  }
38
40