nth_composite.sf 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 06 June 2021
  4. # Edit: 07 July 2022
  5. # https://github.com/trizen
  6. # Return the n-th composite number, using binary search and the prime counting function.
  7. # See also:
  8. # https://oeis.org/A002808
  9. func composite_count_lower(n) {
  10. n - n.prime_count_upper - 1
  11. }
  12. func composite_count_upper(n) {
  13. n - n.prime_count_lower - 1
  14. }
  15. func simple_composite_lower(n) {
  16. int(n + n/log(n) + n/(log(n)**2))
  17. }
  18. func simple_composite_upper(n) {
  19. int(n + n/log(n) + (3*n)/(log(n)**2))
  20. }
  21. func nth_composite_lower(n) {
  22. bsearch_min(simple_composite_lower(n), simple_composite_upper(n), {|k|
  23. composite_count_upper(k) <=> n
  24. })
  25. }
  26. func nth_composite_upper(n) {
  27. bsearch_max(simple_composite_lower(n), simple_composite_upper(n), {|k|
  28. composite_count_lower(k) <=> n
  29. })
  30. }
  31. func nth_composite(n) {
  32. n == 0 && return 1 # not composite, but...
  33. n <= 0 && return NaN
  34. n == 1 && return 4
  35. # Lower and upper bounds from A002808 (for n >= 4).
  36. #var min = int(n + n/log(n) + n/(log(n)**2))
  37. #var max = int(n + n/log(n) + (3*n)/(log(n)**2))
  38. # Better bounds for the n-th composite number
  39. var min = nth_composite_lower(n)
  40. var max = nth_composite_upper(n)
  41. if (n < 4) {
  42. min = 4;
  43. max = 8;
  44. }
  45. var k = 0
  46. var c = 0
  47. loop {
  48. k = (min + max)>>1
  49. c = (k - prime_count(k) - 1)
  50. if (abs(c - n) <= k.iroot(3)) {
  51. break
  52. }
  53. given (c <=> n) {
  54. when (+1) { max = k-1 }
  55. when (-1) { min = k+1 }
  56. else { break }
  57. }
  58. }
  59. if (!k.is_composite) {
  60. --k
  61. }
  62. while (c != n) {
  63. var j = (n <=> c)
  64. k += j
  65. c += j
  66. k += j while !k.is_composite
  67. }
  68. return k
  69. }
  70. for n in (1..10) {
  71. var c = nth_composite(10**n)
  72. assert(c.is_composite)
  73. assert_eq(c.composite_count, 10**n)
  74. assert_eq(10**n -> nth_composite, c)
  75. say "C(10^#{n}) = #{c}"
  76. }
  77. assert_eq(
  78. nth_composite.map(1..100),
  79. 100.by { .is_composite }
  80. )
  81. __END__
  82. C(10^1) = 18
  83. C(10^2) = 133
  84. C(10^3) = 1197
  85. C(10^4) = 11374
  86. C(10^5) = 110487
  87. C(10^6) = 1084605
  88. C(10^7) = 10708555
  89. C(10^8) = 106091745
  90. C(10^9) = 1053422339
  91. C(10^10) = 10475688327
  92. C(10^11) = 104287176419
  93. C(10^12) = 1039019056246
  94. C(10^13) = 10358018863853
  95. C(10^14) = 103307491450820
  96. C(10^15) = 1030734020030318
  97. C(10^16) = 10287026204717358