Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php]losowanie liczb zmienno przecinkowych
Forum PHP.pl > Forum > Przedszkole
-ukaszq-
Chce zrobic taki programik, ktory mi bedzie generował 10 liczb (losowo) z okreslonego przedzialu max i min. Tak aby suma tych liczb wylosowanych podzielona przez 10 dala wynik np 20,3.
Zrobilem tak:


  1. <?php
  2. $i=1;
  3. $srednia="20.3";
  4. $petla = "600";
  5. $max = "21.2";
  6. $min = "20.0";
  7.  
  8. while($i<=10){
  9. $los=rand($min,$max);
  10. echo "$los<br>";
  11. $suma += $los;
  12.  
  13. $i++;
  14. }
  15. $sum=$suma / $petla;
  16. echo round($sum,2);
  17. ?>


Tylko funkcja rand nie widzi mi liczb z dwoma miejscami po przecinku.
No i nie wiem jak to ustalic zeby te liczby daly mi konkretną srednią.
Prosze o pomoc...
marcio
mOZE ZAmiast wyswietlac za pomoca echo sprobuj uzyc sprintf lub printf z operatorem %.2f??
nowotny
rand" title="Zobacz w manualu PHP" target="_manual przyjmuje tylko wartości całkowite... Pomnóż sobie $min i $max przez 10, zapakuj do rand a to co ci rand zwróci podziel przez 10...
Gość
No wpisalem tak pomnozylem przez 10 a pozniej podzielilem. Dzieki
Ale jak zrobic to aby te liczby wygenerowal tak aby wyszedl okreslony przeze mnie wynik z tych liczb?questionmark.gif
ukaszq
Czy zna ktos taką opcje jak to zrobic? By z okreslonej tak podzielil wynik by wyszla okreslona przeze mnie średnia?
Prosze o pomoc...
Hazel
Hehe, z tego co zrozumiałem to strasznie śmieszny problem biggrin.gif
Chcesz po prostu nakazać randomowi żeby wylosował takie liczby, żeby ich średnia była z góry ustalona biggrin.gif
No, powodzenia smile.gif
Nie da się tego w ten sposób zrobić. Random losuje takie liczby, jakie jemu sie podoba i nie możesz mu kazać nic konkretnego losować. Możesz natomiast wylosować jedną liczbę i tak dobrać drugą, żeby ich średnia była taka, jaką byś chciał winksmiley.jpg To jedyny słuszny sposób rozwiązania takiego problemu.
ukaszq
No moze rzeczywiscie.
Ale wiesz... ja tych wyników mam mieć np 600. Zrobilem petle ktora ma generowac takie liczby z przedzialu np 20,0 do 21,6 aby przy sumie 600 wyników srednia dala np 20,9.
Nie wiem jak to rozwizac...
dr_bonzo
  1. <?php
  2. $target_average = 15;
  3. $count = 100;
  4. $min = 10;
  5. $max = 20;
  6. $precision = 3;
  7.  
  8. // ------------
  9. $divider = pow( 10, $precision );
  10. $generator = new AvgGenerator( $target_average, $min, $max, $precision );
  11. $numbers = $generator->generate( $count );
  12.  
  13. stats( $numbers, $precision );
  14.  
  15.  
  16. function stats( $numbers, $precision )
  17. {
  18. $sum = 0.0;
  19. $min = reset( $numbers );
  20. $max = reset( $numbers );
  21. foreach ( $numbers as $n )
  22. {
  23. $sum += $n;
  24. if ( $n < $min )
  25. {
  26. $min = $n;
  27. }
  28.  
  29. if ( $n > $max )
  30. {
  31. $max = $n;
  32. }
  33. }
  34.  
  35. $c = count( $numbers );
  36. $average = $sum / (float)$c;
  37. //printf( "count: %.{$precision}d, average: %.{$precision}f, min: %.{$precision}f, max: %.{$precision}f\n", $c, $average, $min, $max );
  38. }
  39.  
  40. class AvgGenerator
  41. {
  42. private $target_average;
  43. private $min;
  44. private $max;
  45. private $precision;
  46.  
  47. public function __construct( $target_average, $min, $max, $precision )
  48. {
  49. $this->target_average = $target_average;
  50. $this->min = $min;
  51. $this->max = $max;
  52. $this->precision = $precision;
  53. }
  54.  
  55. public function generate( $count )
  56. {
  57. $currentAverage = 0.0;
  58. $currentSum = 0.0;
  59. $numbers = array();
  60. $divider = pow( 10, $this->precision );
  61. $done = 0;
  62. $left = $count;
  63. for ( $i = 0; $i < $count; $i++ )
  64. {
  65. if ( $this->overTargetAverage( $currentAverage ) )
  66. {
  67. $currentMax = $this->countCurrentMax( $currentAverage, $done, $left );
  68. $currentMin = $this->min;
  69.  
  70. }
  71. else
  72. {
  73. $currentMin = $this->countCurrentMin( $currentAverage, $done, $left );
  74. $currentMax = $this->max;
  75. }
  76.  
  77. $done = $i + 1;
  78. $left = $count - $done;
  79. $nextNumber = $this->nextRandomFloat( $currentMin, $currentMax, $divider );
  80. $numbers[] = $nextNumber;
  81. $currentSum += $nextNumber;
  82. $currentAverage = $currentSum / $done;
  83. // printf( "[%d] x = %.3f ; sum = %.3f ; avg = %.3f ; tavg = %.3f<br />", $done, $nextNumber, $currentSum, $currentAverage, $this->target_average );
  84. printf( "%d; %.3f\n", $done, $nextNumber);
  85. }
  86.  
  87. return $numbers;
  88. }
  89.  
  90.  
  91. private function nextRandomFloat( $min, $max, $divider )
  92. {
  93.  
  94. $min = $min * $divider;
  95. $max = $max * $divider;
  96. $x = (float)(rand( 0, $max - $min ) + $min ) / (float)$divider;
  97.  
  98. return $x;
  99. }
  100. private function countCurrentMax( $currentAverage, $done, $left )
  101. {
  102. $targetSum = $this->target_average * ( $done + $left );
  103. $currentSum = $currentAverage * $done + $this->min * ( $left - 1 ); // minimum sum that we may get (excluding current number
  104. $diffSum = $targetSum - $currentSum;
  105. if ( $diffSum < $this->max )
  106. {
  107. return $diffSum;
  108. }
  109. else
  110. {
  111. return $this->max;
  112. }
  113.  
  114. }
  115. private function countCurrentMin( $currentAverage, $done, $left )
  116. {
  117. $targetSum = $this->target_average * ( $done + $left );
  118. $currentSum = $currentAverage * $done + $this->max * ( $left - 1 ); // minimum sum that we may get (excluding current number
  119. $diffSum = $targetSum - $currentSum;
  120. if ( $diffSum > $this->min )
  121. {
  122. return $diffSum;
  123. }
  124. else
  125. {
  126. return $this->min;
  127. }
  128.  
  129. }
  130.  
  131. private function overTargetAverage( $currentAverage )
  132. {
  133. return $currentAverage > $this->target_average;
  134. }
  135.  
  136. private function underTargetAverage( $currentAverage )
  137. {
  138. return $currentAverage < $this->target_average;
  139. }
  140.  
  141.  
  142. }
  143. ?>


+ Trzyma sie sredniej,
- czasami przekracza nieznacznie zalozone min i max, ale nie mam teraz czasu zeby to dokladnie przebadac
- no i wada: koncowe wartosci czesto sa na sile dobierane zeby sie w sredniej zmiescic, np. 5% ostatnich wartosci to np. min lub tylko max

Wynik:
http://sunki.quickshareit.com/share/picture2af6b4.png

dla [10, 20] i sredniej 15 (czyli tak jak w kodzie)
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.