fork download
  1. #include <stdio.h>
  2.  
  3. /**
  4.  * @brief オイラーのφ関数をint型のみで計算する
  5.  * * @param n 計算対象の正の整数
  6.  * @return int オイラーのφ関数の値 (φ(n))
  7.  */
  8. int euler_phi(int n) {
  9. // 負の数やゼロは扱わない
  10. if (n <= 0) {
  11. return 0;
  12. }
  13.  
  14. // φ(1) = 1
  15. if (n == 1) {
  16. return 1;
  17. }
  18.  
  19. int result = n;
  20. int temp_n = n; // 素因数分解用にコピー
  21.  
  22. // 1. i=2 の処理
  23. // 2が因数であれば、φ(n) = φ(n) * (1 - 1/2) の計算を行う
  24. if (temp_n % 2 == 0) {
  25. // result = result / 2 * (2 - 1) = result / 2
  26. result = result / 2;
  27.  
  28. // temp_n から素因数2を完全に取り除く
  29. while (temp_n % 2 == 0) {
  30. temp_n /= 2;
  31. }
  32. }
  33.  
  34. // 2. i=3 以上の奇数の処理
  35. // i*i <= temp_n までループすることで、素数のみを効率的にチェック
  36. for (int i = 3; i * i <= temp_n; i += 2) {
  37. if (temp_n % i == 0) {
  38. // 素因数 i が見つかった場合、計算式を適用
  39. // result = result / i * (i - 1)
  40. result = result / i;
  41. result = result * (i - 1);
  42.  
  43. // temp_n から素因数 i を完全に取り除く
  44. while (temp_n % i == 0) {
  45. temp_n /= i;
  46. }
  47. }
  48. }
  49.  
  50. // 3. ループ終了後、temp_n が 1 より大きければ、残りが最大の素因数
  51. if (temp_n > 1) {
  52. // 残った素因数 temp_n に対して計算を適用
  53. // result = result / temp_n * (temp_n - 1)
  54. result = result / temp_n;
  55. result = result * (temp_n - 1);
  56. }
  57.  
  58. return result;
  59. }
  60.  
  61. int main(void) {
  62. int num;
  63.  
  64. printf("正の整数を入力してください: ");
  65. // 入力が成功し、かつ正の数であることを確認
  66. if (scanf("%d", &num) != 1 || num <= 0) {
  67. printf("無効な入力です。\n");
  68. return 1;
  69. }
  70.  
  71. int euler = euler_phi(num);
  72.  
  73. printf("φ(%d) = %d\n", num, euler);
  74.  
  75. return 0;
  76. }
Success #stdin #stdout 0s 5320KB
stdin
30
stdout
正の整数を入力してください: φ(30) = 8