thamming_thinout.nim 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. discard """
  2. cmd: "nim c --gc:orc -d:nimThinout -r $file"
  3. output: '''The first 20 hammings are: 1 2 3 4 5 MEM IS 0'''
  4. """
  5. # test Nim Hamming Number Lazy List algo with reference counts and not...
  6. # compile with "-d:release -d:danger" and test with various
  7. # memory managment GC's, allocators, threading, etc.
  8. from times import epochTime
  9. from math import log2
  10. # implement our own basic BigInt so the bigints library isn't necessary...
  11. type
  12. BigInt = object
  13. digits: seq[uint32]
  14. let zeroBigInt = BigInt(digits: @[ 0'u32 ])
  15. let oneBigInt = BigInt(digits: @[ 1'u32 ])
  16. proc shladd(bi: var BigInt; n: int; a: BigInt) =
  17. var cry = 0'u64
  18. for i in 0 ..< min(bi.digits.len, a.digits.len):
  19. cry += (bi.digits[i].uint64 shl n) + a.digits[i].uint64
  20. bi.digits[i] = cry.uint32
  21. cry = cry shr 32
  22. if cry > 0'u64:
  23. bi.digits.add cry.uint32
  24. proc `$`(x: BigInt): string =
  25. if x.digits.len == 0 or (x.digits.len == 1 and x.digits[0] == 0'u32):
  26. return "0"
  27. var n = x
  28. var msd = n.digits.high
  29. result = ""
  30. while msd >= 0:
  31. if n.digits[msd] == 0'u32: msd.dec; continue
  32. var brw = 0.uint64
  33. for i in countdown(msd, 0):
  34. let dvdnd = n.digits[i].uint64 + (brw shl 32)
  35. let q = dvdnd div 10'u64; brw = dvdnd - q*10'u64; n.digits[i] = q.uint32
  36. result &= $brw
  37. for i in 0 .. result.high shr 1:
  38. let tmp = result[^(i + 1)]
  39. result[^(i + 1)] = result[i]
  40. result[i] = tmp
  41. proc convertTrival2BigInt(tpl: (uint32, uint32, uint32)): BigInt =
  42. result = oneBigInt
  43. let (x2, x3, x5) = tpl
  44. for _ in 1 .. x2: result.shladd 1, zeroBigInt
  45. for _ in 1 .. x3: result.shladd 1, result
  46. for _ in 1 .. x5: result.shladd 2, result
  47. type LogRep = (float64, (uint32, uint32, uint32))
  48. type LogRepf = proc(x: LogRep): LogRep
  49. const one: LogRep = (0.0f64, (0u32, 0u32, 0u32))
  50. proc `<`(me: LogRep, othr: LogRep): bool = me[0] < othr[0]
  51. const lb2 = 1.0'f64
  52. const lb3 = 3.0'f64.log2
  53. const lb5 = 5.0'f64.log2
  54. proc mul2(me: LogRep): LogRep =
  55. let (lr, tpl) = me; let (x2, x3, x5) = tpl
  56. (lr + lb2, (x2 + 1, x3, x5))
  57. proc mul3(me: LogRep): LogRep =
  58. let (lr, tpl) = me; let (x2, x3, x5) = tpl
  59. (lr + lb3, (x2, x3 + 1, x5))
  60. proc mul5(me: LogRep): LogRep =
  61. let (lr, tpl) = me; let (x2, x3, x5) = tpl
  62. (lr + lb5, (x2, x3, x5 + 1))
  63. type
  64. LazyList = ref object
  65. hd: LogRep
  66. tlf: proc(): LazyList {.closure.}
  67. tl: LazyList
  68. proc rest(ll: LazyList): LazyList = # not thread-safe; needs lock on thunk
  69. if ll.tlf != nil:
  70. ll.tl = ll.tlf()
  71. ll.tlf = nil
  72. ll.tl
  73. iterator hamming(until: int): (uint32, uint32, uint32) =
  74. proc merge(x, y: LazyList): LazyList =
  75. let xh = x.hd
  76. let yh = y.hd
  77. if xh < yh: LazyList(hd: xh, tlf: proc(): auto = merge x.rest, y)
  78. else: LazyList(hd: yh, tlf: proc(): auto = merge x, y.rest)
  79. proc smult(mltf: LogRepf; s: LazyList): LazyList =
  80. proc smults(ss: LazyList): LazyList =
  81. LazyList(hd: ss.hd.mltf, tlf: proc(): auto = ss.rest.smults)
  82. s.smults
  83. proc unnsm(s: LazyList, mltf: LogRepf): LazyList =
  84. var r: LazyList = nil
  85. let frst = LazyList(hd: one, tlf: proc(): LazyList = r)
  86. r = if s == nil: smult mltf, frst else: s.merge smult(mltf, frst)
  87. r
  88. var hmpll: LazyList = ((nil.unnsm mul5).unnsm mul3).unnsm mul2
  89. # var hmpll: LazyList = nil; for m in [mul5, mul3, mul2]: echo one.m # ; hmpll = unnsm(hmpll, m)
  90. yield one[1]
  91. var cnt = 1
  92. while hmpll != nil:
  93. yield hmpll.hd[1]
  94. hmpll = hmpll.rest # almost forever
  95. cnt.inc
  96. if cnt > until: break
  97. #when declared(thinout):
  98. thinout(hmpll)
  99. proc main =
  100. stdout.write "The first 20 hammings are: "
  101. for h in hamming(4):
  102. write stdout, h.convertTrival2BigInt, " "
  103. for h in hamming(200):
  104. discard h.convertTrival2BigInt
  105. let mem = getOccupiedMem()
  106. main()
  107. echo "MEM IS ", getOccupiedMem() - mem
  108. #[
  109. result = (smults, :envP.:up)(rest(:envP.ss2))
  110. proc anon =
  111. var
  112. :tmpD_284230
  113. :tmpD_284233
  114. :tmpD_284236
  115. try:
  116. `=sink_283407`(result_283502,
  117. `=sink_283927`(:tmpD_284236, (smults_283495,
  118. wasMoved_284234(:tmpD_284233)
  119. `=_284014`(:tmpD_284233, :envP_283898.:up_283899)
  120. :tmpD_284233))
  121. :tmpD_284236(
  122. `=sink_283407`(:tmpD_284230, rest_283366(:envP_283898.ss2_-283497))
  123. :tmpD_284230))
  124. finally:
  125. `=destroy_283914`(:tmpD_284236)
  126. `=destroy_283388`(:tmpD_284230)
  127. proc smuls(ss: LazyList_283350; :envP_283891): LazyList_283350 =
  128. var :env_283913
  129. try:
  130. `=destroy_283951`(:env_283913)
  131. internalNew_43643(:env_283913)
  132. `=_283401`(:env_283913.ss2_-283497, ss_283497)
  133. :env_283913.:up_283899 = :envP_283891
  134. `=sink_283407`(result_283498, LazyList_283350(hd_283353: :envP_283891.mltf1_-283492(
  135. :env_283913.ss2_-283497.hd_283353), tlf_283356: (:anonymous_283499,
  136. let blitTmp_284227 = :env_283913
  137. wasMoved_284228(:env_283913)
  138. blitTmp_284227)))
  139. finally:
  140. `=destroy_283951`(:env_283913)
  141. proc smul =
  142. var
  143. :env_283969
  144. :tmpD_284220
  145. try:
  146. `=destroy_284008`(:env_283969)
  147. internalNew_43643(:env_283969)
  148. `=_283976`(:env_283969.mltf1_-283492, mltf_283492)
  149. proc smults(ss: LazyList_283350; :envP_283891): LazyList_283350 =
  150. result_283498 = LazyList_283350(hd_283353: mltf_283492(ss_283497.hd_283353), tlf_283356: proc (
  151. :envP_283898): auto_43100 = result_283502 = smults_283495(rest_283366(ss_283497)))
  152. `=sink_283407`(result_283494,
  153. `=sink_283927`(:tmpD_284220, (smults_283495,
  154. let blitTmp_284218 = :env_283969
  155. wasMoved_284219(:env_283969)
  156. blitTmp_284218))
  157. :tmpD_284220(s_283493))
  158. finally:
  159. `=destroy_283914`(:tmpD_284220)
  160. `=destroy_284008`(:env_283969)
  161. ]#