Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
3.7 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. peakfind.cpp
  5. Abstract:
  6. SIS Groveler peak finder
  7. Authors:
  8. John Douceur, 1998
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "all.hxx"
  14. PeakFinder::PeakFinder(
  15. double accuracy,
  16. double range)
  17. {
  18. ASSERT(this != 0);
  19. ASSERT(accuracy > 0.0);
  20. ASSERT(accuracy < 1.0);
  21. ASSERT(range > 0.0);
  22. base = 1.0 + 2.0 * accuracy / (1.0 - accuracy);
  23. ASSERT(base >= 1.0);
  24. multiplier = 1.0 / log(base);
  25. num_bins = int(multiplier * log(range)) + 1;
  26. ASSERT(num_bins > 0);
  27. bins = new int[num_bins];
  28. target_sample_size = int(1.0 / (accuracy * accuracy));
  29. ASSERT(target_sample_size > 0);
  30. reset();
  31. ASSERT(floor_value >= 0.0);
  32. ASSERT(sample_size >= 0);
  33. ASSERT(total_weight >= 0);
  34. }
  35. PeakFinder::~PeakFinder()
  36. {
  37. ASSERT(this != 0);
  38. ASSERT(num_bins > 0);
  39. ASSERT(bins != 0);
  40. ASSERT(base >= 1.0);
  41. ASSERT(target_sample_size > 0);
  42. ASSERT(floor_value >= 0.0);
  43. ASSERT(sample_size >= 0);
  44. ASSERT(total_weight >= 0);
  45. delete[] bins;
  46. bins = 0;
  47. }
  48. void
  49. PeakFinder::reset()
  50. {
  51. ASSERT(this != 0);
  52. ASSERT(num_bins > 0);
  53. ASSERT(bins != 0);
  54. ASSERT(base >= 1.0);
  55. ASSERT(target_sample_size > 0);
  56. floor_exp = int(multiplier * log(DBL_MAX));
  57. floor_value = pow(base, floor_exp);
  58. ASSERT(floor_value >= 0.0);
  59. sample_size = 0;
  60. total_weight = 0;
  61. }
  62. void
  63. PeakFinder::sample(
  64. double value,
  65. int weight)
  66. {
  67. ASSERT(this != 0);
  68. ASSERT(num_bins > 0);
  69. ASSERT(bins != 0);
  70. ASSERT(base >= 1.0);
  71. ASSERT(target_sample_size > 0);
  72. ASSERT(floor_value >= 0.0);
  73. ASSERT(sample_size >= 0);
  74. ASSERT(total_weight >= 0);
  75. ASSERT(value >= 0);
  76. ASSERT(weight > 0);
  77. if (value <= 0.0)
  78. {
  79. return;
  80. }
  81. if (value < floor_value)
  82. {
  83. int new_exp = int(multiplier * log(value));
  84. double new_floor = pow(base, new_exp);
  85. int shift = __min(floor_exp - new_exp, num_bins);
  86. for (int index = num_bins - shift - 1; index >= 0; index--)
  87. {
  88. bins[index + shift] = bins[index];
  89. }
  90. for (index = 0; index < shift; index++)
  91. {
  92. bins[index] = 0;
  93. }
  94. floor_exp = new_exp;
  95. floor_value = new_floor;
  96. }
  97. int bin_index = __max(int(multiplier * log(value / floor_value)), 0);
  98. if (bin_index < num_bins)
  99. {
  100. bins[bin_index] += weight;
  101. }
  102. ASSERT(total_weight >= 0);
  103. total_weight += weight;
  104. sample_size++;
  105. }
  106. bool
  107. PeakFinder::found() const
  108. {
  109. ASSERT(this != 0);
  110. ASSERT(num_bins > 0);
  111. ASSERT(bins != 0);
  112. ASSERT(base >= 1.0);
  113. ASSERT(target_sample_size > 0);
  114. ASSERT(floor_value >= 0.0);
  115. ASSERT(sample_size >= 0);
  116. ASSERT(total_weight >= 0);
  117. return sample_size > target_sample_size;
  118. }
  119. double
  120. PeakFinder::mode() const
  121. {
  122. ASSERT(this != 0);
  123. ASSERT(num_bins > 0);
  124. ASSERT(bins != 0);
  125. ASSERT(base >= 1.0);
  126. ASSERT(target_sample_size > 0);
  127. ASSERT(floor_value >= 0.0);
  128. ASSERT(sample_size >= 0);
  129. ASSERT(total_weight >= 0);
  130. double bin_width = base - 1.0;
  131. int max_index = -1;
  132. double max_height = 0.0;
  133. for (int index = 0; index < num_bins; index++)
  134. {
  135. double height = double(bins[index]) / bin_width;
  136. if (height > max_height)
  137. {
  138. max_index = index;
  139. max_height = height;
  140. }
  141. bin_width *= base;
  142. }
  143. if (max_index < 0)
  144. {
  145. return 0.0;
  146. }
  147. else
  148. {
  149. return 2 * base / (base + 1.0) * floor_value * pow(base, max_index);
  150. }
  151. }
  152. double
  153. PeakFinder::median() const
  154. {
  155. ASSERT(this != 0);
  156. ASSERT(num_bins > 0);
  157. ASSERT(bins != 0);
  158. ASSERT(base >= 1.0);
  159. ASSERT(target_sample_size > 0);
  160. ASSERT(floor_value >= 0.0);
  161. ASSERT(sample_size >= 0);
  162. ASSERT(total_weight >= 0);
  163. double remaining_weight = 0.5 * double(total_weight);
  164. for (int index = 0; index < num_bins; index++)
  165. {
  166. double current_weight = double(bins[index]);
  167. if (current_weight > remaining_weight)
  168. {
  169. return (1.0 + remaining_weight * (base - 1.0) / current_weight)
  170. * floor_value * pow(base, index);
  171. }
  172. remaining_weight -= current_weight;
  173. }
  174. return 0.0;
  175. }