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

回答編集履歴

3

add_rが単純末尾再帰になっとらんかったのを修正

2018/11/04 02:41

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -45,7 +45,7 @@
45
45
  {
46
46
  if (b == 0) return a;
47
47
  assert(b > 0);
48
- return add(++a, --b);
48
+ return add_r(++a, --b);
49
49
  }
50
50
 
51
51
  int add(int a, int b)

2

スタックオーバーフローなど不要、そう、tertailがあればね

2018/11/04 02:41

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -100,4 +100,4 @@
100
100
  }
101
101
  ```
102
102
 
103
- `div()`は、0除算でエラーにならない事を除き、標準の`/`と動作を合わせたつもりです、たぶん。**速度は全く考慮に入れていません。**`assert()`を有効にしたい場合は`#define NDEBUG`をコメントアウトしてください。ビット演算子やシフト演算子の実装については力尽きましたので、誰かがやってくれることでしょう。
103
+ `div()`は、0除算でエラーにならない事を除き、標準の`/`と動作を合わせたつもりです、たぶん。**速度は全く考慮に入れていません。**インクリメントのオーバーフローやデクリメントのアンダーフローは考慮していませんが、末尾再帰になっていますので、適当に最適化オプションを付けていればスタックオーバーフローは起きないはずです。`assert()`を有効にしたい場合は`#define NDEBUG`をコメントアウトしてください。ビット演算子やシフト演算子の実装については力尽きましたので、誰かがやってくれることでしょう。

1

ソースコード変更

2018/11/04 02:38

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -1,48 +1,103 @@
1
- インクリメントとデクリメントだけで四則演算を全て実装してみました。
1
+ インクリメントとデクリメントだけで四則演算を全て実装してみました。算術演算子禁止として、[Arithmetic operators - cppreference.com](https://en.cppreference.com/w/c/language/operator_arithmetic)にある全ての演算子を使用しないようにしました。また、`while`や`for`および`goto`を用いたループも禁止しました。
2
2
 
3
3
  ```C
4
+ /**
5
+ * Implementation of arithmetic operators without using arithmetic operators.
6
+ * https://en.cppreference.com/w/c/language/operator_arithmetic
7
+ */
8
+
9
+ #define NDEBUG
10
+ #include <assert.h>
4
11
  #include <stdio.h>
5
12
 
13
+ int plu(int a); // +a
14
+ int min(int a); // -a
6
- int add(int a, int b);
15
+ int add(int a, int b); // a + b
7
- int sub(int a, int b);
16
+ int sub(int a, int b); // a - b
17
+ int pro(int a, int b); // a * b
18
+ int div(int a, int b); // a / b
8
- int mul(int a, int b);
19
+ int mod(int a, int b); // a % b
9
- int div(int a, int b);
10
20
 
21
+ int plu(int a) { return a; }
22
+
23
+ static inline int min_inc_r(int a, int b)
24
+ {
25
+ if (a == 0) return b;
26
+ assert(a < 0);
27
+ return min_inc_r(++a, ++b);
28
+ }
29
+
30
+ static inline int min_dec_r(int a, int b)
31
+ {
32
+ if (a == 0) return b;
33
+ assert(a > 0);
34
+ return min_dec_r(--a, --b);
35
+ }
36
+
37
+ int min(int a)
38
+ {
39
+ if (a == 0) return 0;
40
+ if (a < 0) return min_inc_r(a, 0);
41
+ return min_dec_r(a, 0);
42
+ }
43
+
44
+ static inline int add_r(int a, int b)
45
+ {
46
+ if (b == 0) return a;
47
+ assert(b > 0);
48
+ return add(++a, --b);
49
+ }
50
+
11
51
  int add(int a, int b)
12
52
  {
13
- if (b == 0) return a;
14
- if (b < 0) return -add(-a, -b);
53
+ if (b < 0) return min(add(min(a), min(b)));
15
- return add(++a, --b);
54
+ return add_r(a, b);
16
55
  }
17
56
 
18
- int sub(int a, int b)
57
+ int sub(int a, int b) { return add(a, min(b)); }
58
+
59
+ static inline int pro_r(int a, int b, int r)
19
60
  {
61
+ if (b == 0) return r;
62
+ assert(b > 0);
20
- return add(a, -b);
63
+ return pro_r(a, --b, add(r, a));
21
64
  }
22
65
 
23
- int mul(int a, int b)
66
+ int pro(int a, int b)
24
67
  {
25
- if (b == 0) return 0;
68
+ if (b == 0) return 0;
26
- if (b < 0) return mul(-a, -b);
69
+ if (b < 0) return pro(min(a), min(b));
27
- return add(mul(a, --b), a);
70
+ return pro_r(a, b, 0);
28
71
  }
29
72
 
73
+ static inline int div_r(int a, int b, int r)
74
+ {
75
+ assert(b > 0);
76
+ if (a == 0) return r;
77
+ if (a < 0) return --r;
78
+ return div_r(sub(a, b), b, ++r);
79
+ }
80
+
30
81
  int div(int a, int b)
31
82
  {
32
- if (b == 0) return 0; // or error
83
+ if (b == 0) return 0; // or error
33
- if (b < 0) return div(-a, -b);
84
+ if (b < 0) return min(div(a, min(b)));
34
- if (a < 0) return -div(-a, b);
85
+ if (a < 0) return min(div(min(a), b));
35
- if (a < b) return 0;
36
- return add(div(a - b, b), 1);
86
+ return div_r(a, b, 0);
37
87
  }
38
88
 
89
+ int mod(int a, int b) { return sub(a, pro(div(a, b), b)); }
90
+
39
91
  int main(void)
40
92
  {
93
+ printf("+42 = %d\n", plu(42));
94
+ printf("-42 = %d\n", min(42));
41
- printf("%d\n", add(6, 7));
95
+ printf("7 + 6 = %d\n", add(7, 6));
42
- printf("%d\n", sub(6, 7));
96
+ printf("7 - 6 = %d\n", sub(7, 6));
97
+ printf("7 * 6 = %d\n", pro(7, 6));
98
+ printf("7 / 6 = %d\n", div(7, 6));
43
- printf("%d\n", mul(6, 7));
99
+ printf("7 %% 6 = %d\n", mod(7, 6));
44
- printf("%d\n", div(6, 7));
45
100
  }
46
101
  ```
47
102
 
48
- `div()`は標準の`div()`と動作を合わせたつもりです、たぶん。**速度は全く考慮に入れていません。**`mul()``div()`の再帰部分は最適化れなみたですので、**数大きいとスタックオーバーフローで落ちます。**末尾再帰になように`mul()``div()`を書き直せば落ちないようにはきるはずです
103
+ `div()`は、0除算でエラーにならない事を除き、標準の`/`と動作を合わせたつもりです、たぶん。**速度は全く考慮に入れていません。**`assert()`を有効にしたい場合は`#define NDEBUG`をコメントアウトしてください。ビット演算子やシフト演算子の実装につては力尽きましたので、誰かやってくれとでしょう