I found a lot of information and script examples around that showed how to rate limit the users of an API but I wasn't able to find any examples of how to rate limit your own requests of an API when these limits are imposed.
I've always rate limited my scripts with code such as sleep or usleep commands but it feels like an inefficient way of doing things, especially when the API endpoints have pretty high rate limits and hammering API's until you hit the limits is also inefficient.
For example, Google's API limits vary based on the API you are using and can increase/decrease, in this case a fixed rate limit hard coded into the code just seems like primitive guess work!
Have I missed something pretty obvious? Or is this just not as common as I expect it to be?
Okay, for giggles I've thrown together a limiter class that will allow you to specify the limit per second, minute and hour. I can't resist having a good reason to use a circular queue!
If you have multiple processes doing the consumption, whether simultaneous or not, you'll have to devise a way to store and/or share the usage history on your own.
// LIMITER.PHP
class Limiter
{
private $queue = array();
private $size;
private $next;
private $perSecond;
private $perMinute;
private $perHour;
// Set any constructor parameter to non-zero to allow adherence to the
// limit represented. The largest value present will be the size of a
// circular queue used to track usage.
// -------------------------------------------------------------------
function __construct($perSecond=0,$perMinute=0,$perHour=0)
{
$this->size = max($perSecond,$perMinute,$perHour);
$this->next = 0;
$this->perSecond = $perSecond;
$this->perMinute = $perMinute;
$this->perHour = $perHour;
for($i=0; $i < $this->size; $i++)
$this->queue[$i] = 0;
}
// See if a use would violate any of the limits specified. We return true
// if a limit has been hit.
// ----------------------------------------------------------------------
public function limitHit($verbose=0)
{
$inSecond = 0;
$inMinute = 0;
$inHour = 0;
$doneSecond = 0;
$doneMinute = 0;
$doneHour = 0;
$now = microtime(true);
if ( $verbose )
echo "Checking if limitHit at $now<br>\n";
for ($offset=1; $offset <= $this->size; $offset++)
{
$spot = $this->next - $offset;
if ( $spot < 0 )
$spot = $this->size - $offset + $this->next;
if ( $verbose )
echo "... next $this->next size $this->size offset $offset spot $spot utime " . $this->queue[$spot] . "<br>\n";
// Count and track within second
// -----------------------------
if ( $this->perSecond && !$doneSecond && $this->queue[$spot] >= microtime(true) - 1.0 )
$inSecond++;
else
$doneSecond = 1;
// Count and track within minute
// -----------------------------
if ( $this->perMinute && !$doneMinute && $this->queue[$spot] >= microtime(true) - 60.0 )
$inMinute++;
else
$doneMinute = 1;
// Count and track within hour
// ---------------------------
if ( $this->perHour && !$doneHour && $this->queue[$spot] >= microtime(true) - 3600.0 )
$inHour++;
else
$doneHour = 1;
if ( $doneSecond && $doneMinute && $doneHour )
break;
}
if ( $verbose )
echo "... inSecond $inSecond inMinute $inMinute inHour $inHour<br>\n";
if ( $inSecond && $inSecond >= $this->perSecond )
{
if ( $verbose )
echo "... limit perSecond hit<br>\n";
return TRUE;
}
if ( $inMinute && $inMinute >= $this->perMinute )
{
if ( $verbose )
echo "... limit perMinute hit<br>\n";
return TRUE;
}
if ( $inHour && $inHour >= $this->perHour )
{
if ( $verbose )
echo "... limit perHour hit<br>\n";
return TRUE;
}
return FALSE;
}
// When an API is called the using program should voluntarily track usage
// via the use function.
// ----------------------------------------------------------------------
public function usage()
{
$this->queue[$this->next++] = microtime(true);
if ( $this->next >= $this->size )
$this->next = 0;
}
}
// ##############################
// ### Test the limiter class ###
// ##############################
$psec = 2;
$pmin = 4;
$phr = 0;
echo "Creating limiter with limits of $psec/sec and $pmin/min and $phr/hr<br><br>\n";
$monitorA = new Limiter($psec,$pmin,$phr);
for ($i=0; $i<15; $i++)
{
if ( !$monitorA->limitHit(1) )
{
echo "<br>\n";
echo "API call A here (utime " . microtime(true) . ")<br>\n";
echo "Voluntarily registering usage<br>\n";
$monitorA->usage();
usleep(250000);
}
else
{
echo "<br>\n";
usleep(500000);
}
}
In order to demonstrate it in action I've put in some "verbose mode" statements in the limit checking function. Here is some sample output.
Creating limiter with limits of 2/sec and 4/min and 0/hr
Checking if limitHit at 1436267440.9957
... next 0 size 4 offset 1 spot 3 utime 0
... inSecond 0 inMinute 0 inHour 0
API call A here (utime 1436267440.9957)
Voluntarily registering usage
Checking if limitHit at 1436267441.2497
... next 1 size 4 offset 1 spot 0 utime 1436267440.9957
... next 1 size 4 offset 2 spot 3 utime 0
... inSecond 1 inMinute 1 inHour 0
API call A here (utime 1436267441.2497)
Voluntarily registering usage
Checking if limitHit at 1436267441.5007
... next 2 size 4 offset 1 spot 1 utime 1436267441.2497
... next 2 size 4 offset 2 spot 0 utime 1436267440.9957
... next 2 size 4 offset 3 spot 3 utime 0
... inSecond 2 inMinute 2 inHour 0
... limit perSecond hit
Checking if limitHit at 1436267442.0007
... next 2 size 4 offset 1 spot 1 utime 1436267441.2497
... next 2 size 4 offset 2 spot 0 utime 1436267440.9957
... next 2 size 4 offset 3 spot 3 utime 0
... inSecond 1 inMinute 2 inHour 0
API call A here (utime 1436267442.0007)
Voluntarily registering usage
Checking if limitHit at 1436267442.2507
... next 3 size 4 offset 1 spot 2 utime 1436267442.0007
... next 3 size 4 offset 2 spot 1 utime 1436267441.2497
... next 3 size 4 offset 3 spot 0 utime 1436267440.9957
... next 3 size 4 offset 4 spot 3 utime 0
... inSecond 1 inMinute 3 inHour 0
API call A here (utime 1436267442.2507)
Voluntarily registering usage
Checking if limitHit at 1436267442.5007
... next 0 size 4 offset 1 spot 3 utime 1436267442.2507
... next 0 size 4 offset 2 spot 2 utime 1436267442.0007
... next 0 size 4 offset 3 spot 1 utime 1436267441.2497
... next 0 size 4 offset 4 spot 0 utime 1436267440.9957
... inSecond 2 inMinute 4 inHour 0
... limit perSecond hit
Checking if limitHit at 1436267443.0007
... next 0 size 4 offset 1 spot 3 utime 1436267442.2507
... next 0 size 4 offset 2 spot 2 utime 1436267442.0007
... next 0 size 4 offset 3 spot 1 utime 1436267441.2497
... next 0 size 4 offset 4 spot 0 utime 1436267440.9957
... inSecond 2 inMinute 4 inHour 0
... limit perSecond hit
Checking if limitHit at 1436267443.5027
... next 0 size 4 offset 1 spot 3 utime 1436267442.2507
... next 0 size 4 offset 2 spot 2 utime 1436267442.0007
... next 0 size 4 offset 3 spot 1 utime 1436267441.2497
... next 0 size 4 offset 4 spot 0 utime 1436267440.9957
... inSecond 0 inMinute 4 inHour 0
... limit perMinute hit
Checking if limitHit at 1436267444.0027
... next 0 size 4 offset 1 spot 3 utime 1436267442.2507
... next 0 size 4 offset 2 spot 2 utime 1436267442.0007
... next 0 size 4 offset 3 spot 1 utime 1436267441.2497
... next 0 size 4 offset 4 spot 0 utime 1436267440.9957
... inSecond 0 inMinute 4 inHour 0
... limit perMinute hit
Well, first things first - you should call any external API's only when you actually need to - the providers will thank you dearly.
There is two ways I usually "impose" a limit on my own API usage - if possible, cache the result for N amount of time, usually a lot less than hard limit of the API itself. This, however, works only in very specific cases.
The second is persistent/semi-persistent counters, where you store a counter in some sort of memory backend along with time when the limiting period begins. Every time before calling API check the storage and see whether the current time minus interval begin and number of requests you have already made is less than imposed by API. If it is, you can make a request - if the interval is larger, you can reset the limit, and if your next request will exceed the limit, and you are still in the previous interval, you can show a pretty error. On each external request then update the interval time if it's exceeded and increment the counter.
Wrap your API calls with Jobs and push them to separate queue:
ApiJob::dispatch()->onQueue('api');
Use queue rate limiting with Redis or with mxl/laravel-queue-rate-limit package (I'm the author). See also SO answer about its usage.
If using mxl/laravel-queue-rate-limit then after its setup run queue worker:
$ php artisan queue:work --queue api
I think we can not answer your question in a few sentences . It takes a true reflection of architecture linked to your application . For me to make an API rate limit for repeat I use caches that store values and utilization of my API. I have to date found no code ready .
Related
I would like to understand recursion fully. I understand the part where it has to meet the base case (n=0) before returning 1, that part I understand completely. When it meets the base case condition, it returns to the instance that called it which is n=1, that I also understand.
How does it now increment and goes back to n=2, how does the mechanism behind it work to make it go back up to n=5? I guess I am missing something here.
<?php
function factorial( $n ) {
// Base case
if ( $n == 0 ) {
echo "Base case: $n = 0. Returning 1...<br>";
return 1;
}
// Recursion
echo "$n = $n: Computing $n * factorial( " . ($n-1) . " )...<br>";
$result = $n * factorial( $n-1 );
echo "Result of $n * factorial( " . ($n-1) . " ) = $result. Returning $result...<br>";
return $result;
}
echo "The factorial of 5 is: " . factorial( 5 );
?>
This is supposed to be the output
5 = 5: Computing 5 * factorial( 4 )...
4 = 4: Computing 4 * factorial( 3 )...
3 = 3: Computing 3 * factorial( 2 )...
2 = 2: Computing 2 * factorial( 1 )...
1 = 1: Computing 1 * factorial( 0 )...
Base case: 0 = 0. Returning 1...
Result of 1 * factorial( 0 ) = 1. Returning 1...
Result of 2 * factorial( 1 ) = 2. Returning 2...
Result of 3 * factorial( 2 ) = 6. Returning 6...
Result of 4 * factorial( 3 ) = 24. Returning 24...
Result of 5 * factorial( 4 ) = 120. Returning 120...
The factorial of 5 is: 120
All the data related to your function or method when it is called is stored on a stack. So let us say you make a call to your function factorial(5) for value 5. Now when you call your function with parameter 5. It is put onto the stack and the program tries to calculate its value, now while calculating it value your program finds out that its value depends on factorial(5-1) that is 5*factorial(4) so overall computation of calculating factorial(5) is stopped it remains in stack and your program will calculate value of factorial(4) by putting it in stack. In order to determine factorial(4) , your program will need value of factorial(3) and therefore i.e will put onto the stack , So the current stack will look somewhat like [[factorial(5) with all its data] , [factorial(4) with all its data] , [factorial(3) with all its data]] Overall state of the whole function is maintained similarly your program will further put factorial(2) and factorial(1) onto the stack. Now if there will be no base condition then your program will crash due to stackoverflow as your program will keep on filling the stack with other function calls like factorial(0) , factorial(-1) and so on. So we need a base case. So when your program finds the condition where n==0 it gets it value directly as and it stops further pushing other function calls to stack and then it starts processing the current stack so once it gets value of factorial(0) it uses it to calculate value of factorial(1) and pops factorial(1) and all its data from the stack after returning the value of facotrial(1) to factorial(2) (as factorial(1) was called from factorial(2) ) now factorial(2) does the same thing. So finally the stack will pop the elements from it as they were pushed and the final value of your function which you called initially will be calculated i.e. factorial(5) .
Let’s say I have a series of numbers like:
12345678910111213141516... (until unlimited)
Then I would like to get a number from it by given digit. For example:
Digit 10th: 1
Digit 17th: 3
...
I have tried to make the algorithm to do it by using PHP but it always showed me an error due to the looping that I made was out of memory size if the given digit that I gave is more than 10.000.000. Allowed Memory Size of 134217728 Bytes Exhausted
How do I deal with this without having to modify memory_limit on php.ini file?
Here are what I have tried to figure the algorithm out: I benchmark the maximum of upper limit of the loop that my local machine could handle, and I found out it's 10.000.000, then I assumed I need to make a separate loop if the given digit/parameter is more than 10.000.000. But in the end I still got that error of out of memory size. Really grateful in advance.
<?php
/*
* benchmark result:
* max digit = 10.000.000
*/
$benchmarkedDigit = 10000000;
$digit = 1000000000000; // it could be dynamically assigned, i.e. a parameter. In this case will show an error since the given digit is 10 trillion
$s = '';
if ($digit > $benchmarkedDigit) {
$mod = fmod($digit, $benchmarkedDigit);
$div = $digit / $benchmarkedDigit;
for ($x = 1; $x <= $div; $x++) {
$upperLimit = ($x * $benchmarkedDigit);
for ($y = ($upperLimit - $benchmarkedDigit + 1); $y <= $upperLimit; $y++) {
$s .= $y;
}
// so it could be:
// 1 - 10.000.000
// 10.000.001 - 20.000.000
// 20.000.001 - 30.000.000
// ...
}
// loop for the rest of the fmod(), if its result is not 0
for ($i = ($upperLimit + 1); $i <= ($upperLimit + $mod); $i++) {
$s .= $i;
}
} else {
for ($x = 1; $x <= $digit; $x++) {
$s .= $x;
}
}
echo substr($s, ($digit - 1), 1);
You can use the fact that there's always 10^n - 10^(n-1) number of n-digit long numbers (even 1 digit, because I see 0 is not there).
With this knowledge, you can skip potentially huge number of numbers.
You start with n=1, and check if the number of n digit numbers is lower than the desired digit. If it is, then reduce the number of n digit numbers from the desired number, increase n by one and start again.
For example: you want to know the 512th digit in that number
Is the number of 1 digit numbers (10) lower than the desired digit (512)?
Yes, so the desired digit should be reduced by that many (512 - 9).
Is the number of 2 digit numbers (90) lower than the desired digit (503 now)?
Yes, so the desired digit should be reduced by that many (503 - 90).
Is the number of 3 digit numbers (900) lower than the desired digit(413 now)?
No, so the desired digit is one of the digits of a 3 digit number.
413 / 3 is 137 (rounded down), so it's one of the digits of the 137th 3 digit numbers (so 237).
413 % 3 (modulo) is 2, so it's the 2nd digit, so it's supposed to be 3.
There can be miscalculations in this, but the overall logic should not be far.
Edit: you could also use a generator, but this can increase the runtime for big numbers
function getNthDigit() {
for ($i = 0;; ++$i) { // Start with 0, which is the 0-th digit
foreach (str_split((string)$i) as $digit) {
yield $digit;
}
}
}
$desiredDigit = 512;
foreach (getNthDigit() as $number => $digit) {
if ($number == $desiredDigit) {
break;
}
}
// $digit should be the desired digit
<?php
function getDigit($Nth){
if($Nth < 10) return $Nth;
$no_of_digits = 1;
$current_contribution = 9;
$actual_length = 9;
$prev_length = 0;
$starting_number = 1;
$power_of_10 = 1;
while($actual_length < $Nth){
$no_of_digits++;
$current_contribution *= 10;
$prev_length = $actual_length;
$actual_length += ($current_contribution * $no_of_digits);
$power_of_10 *= 10;
$starting_number *= 10;
}
$Nth = $Nth - $prev_length;
$offset = $Nth % $no_of_digits === 0 ? intval($Nth / $no_of_digits) - 1 : intval($Nth / $no_of_digits);
$number = strval($starting_number + $offset);
for($i=1;$i<=$no_of_digits;++$i){
if(($Nth - $i) % $no_of_digits === 0){
return $number[$i-1];
}
}
}
// first 100 Digits
for($i=1;$i<=100;++$i){
echo getDigit($i),PHP_EOL;
}
Demo: https://3v4l.org/3l0I7
Algorithm:
To find the nth digit, we will first find the number and then which digit of that number to choose as an answer.
Find the number:
If we carefully observe, the series increases in a sequential manner, such as shown in the table.
Table:
| Digits| Total numbers(of current digit)| Total Digits | Total digits of whole string |
|-------|--------------------------------|--------------|-------------------------------|
| 1 | 9 | 9 | 9 |
| 2 | 90 | 180 | 189 |
| 3 | 900 | 2700 | 2889 |
| 4 | 9000 | 36000 | 38889 |
The above table shows us that if we want to find, let's say 500th digit, then it's some digit of 3 digit number. If we go for 17th digit, then it's some digit of a 2 digit number and so on.
Now, let's take 200th digit as an example. Since it's less than 2889 and greater than 189, it's from a 3 digit number.
What we would do is breakdown the 200 into a smaller number such as 200 - 189 = 11. This 11 means that it's 11th digit of some 3 digit number which started with initial 3 digit number of 100(the starting number for 3 digit).
Now, we do 11 / 3(where 3 is number of digits) and get the quotient as 3. This 3 means that it's 3 numbers past the starting number 100, which we can say as 100 + 3 = 103(since it's 100,101,102 and then the 4th one as 103).
Now, we came to know that the number is 103. All is left to find out is which digit from 103.
Note that sometimes we come across a corner case of even divisibility such as 12 / 3. In this case, we subtract 1 from the quotient since our series of 3 digits starts from 100 and not 101( and so on and so forth for other digits).
Find out the digit:
Now, we know that the number is 103 for a 200 th digit( a.k.a 11 as we calculated above). To find out which one, we write down numbers of 3 digits in sequence and closely observe them.
Sequence:
1 0 0 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 1 0 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
If you observe, you can understand that the most MSB digit follows a sequence of 1,4,7,10,13 etc. Second most MSB follows a sequence of 2,5,8,11,14 etc and the last MSB(which is LSB) follows a sequence of 3,6,9,12,15 etc.
So, from th above sequence, it's pretty evident that 11(which we got after breaking down 200 initially) belongs to a sequence of the 2nd most MSB digit.
So, the final answer from 103 is 0 (the 2nd digit from left).
$num = '12345678910111213141516';
echo $num[16];
Result: 3
I wrote a sudoku generator that creates numbers cell by cell and checks immediately after a cell has been created if it is valid (horizontally, vertically and in a 3x3 block).
Now my problem is that the algorithm always gets stuck at some point, as it won't find a valid number for the current cell. Sometimes closer to the end, sometimes already after writing 30 cells.
This is my function to check the cell, which should change the number depending on its validity:
private function checkCell($index)
{
while ($this->isValid($index) === false) {
$this->cell[$index]->setValue(rand(1, 9));
$this->counter++;
echo 'counter: ' . $this->counter;
echo PHP_EOL;
if ($this->counter > 1000) {
$this->display();
die();
}
}
}
isValid() checks if the cell is valid horizontally, vertically and in a block (this is currently not working, it just returns true).
The counter is for debugging purposes so I can see when it gets stuck.
Here is the function generating my cells:
private function fillCell($index)
{
$rand = rand(1, 9);
$this->cell[$index]->setValue($rand);
$this->checkCell($index);
}
What should be changed so the algorithm doesn't get stuck all the time?
The issue might be that the algorithm is a little too random. You end up creating a grid that is invalid and can not be completed further.
I would propose starting from a known valid grid and shuffle the cells randomly. If a cell can't be moved, we can simply skip it.
A fair warning to the reader, the following will contain pseudo code rather than working code.
A perfectly valid starting grid:
1 2 3 | 4 5 6 | 7 8 9
7 8 9 | 1 2 3 | 4 5 6
4 5 6 | 7 8 9 | 1 2 3
------|-------|------
9 1 2 | 3 4 5 | 6 7 8
6 7 8 | 9 1 2 | 3 4 5
3 4 5 | 6 7 8 | 9 1 2
------|-------|------
8 9 1 | 2 3 4 | 5 6 7
5 6 7 | 8 9 1 | 2 3 4
2 3 4 | 5 6 7 | 8 9 1
We can store this in a single dimension array, as you already appear to do.
We follow a simple logic:
We create a single dimension array containing the cells
$cells = array(
1,2,3,4,5,6,7,8,9,7,8,9,1,2,3,4,5,6,4,5,6,7,8,9,1,2,3,
9,1,2,3,4,5,6,7,8,6,7,8,9,1,2,3,4,5,3,4,5,6,7,8,9,1,2,
8,9,1,2,3,4,5,6,7,5,6,7,8,9,1,2,3,4,2,3,4,5,6,7,8,9,1,
);
We create another array containing numbers from 0 to 80 in a random order, which are the indexes of $cells
$indexes = range(0, 80);
shuffle($indexes);
We iterate over $indexes and use the value to select a random $cell in $cells
foreach($indexes as $index) {
$cell = $cells[$index];
}
For each $cell, we iterate over $cells. In each iteration, we create a temporary grid where we switch the value of the current cell with the value of the target cell. If the temporary grid is valid, we save the target index in an array of candidates
// pseudo code because that's a lot of work
$candidates = getCandidates($cell, $cells);
We randomly choose one of the candidates and switch the cells. If no candidate is available, we simply ignore this step
candidatesCount = count(candidates);
if(candidatesCount > 0) {
$candidate = $candidates[range(0, candidatesCount -1)];
// switch values
$cells[$index] = $cells[$candidate];
$cells[candidate] = $cell;
}
Repeat until $cells is processed
There are likely more efficient ways to proceed, but this logic can not get stuck.
Note that there is a low probability that the shuffle will undo itself and produce the original grid. But it's still a valid grid.
You never want to make a backtracking algorithm that uses random numbers. It can end up running infinitely.
What you want to do is:
Find the first empty cell
Try all possible values from 1 to 9 in this cell. When all values are tried, go back.
For every value you try in the cell (at step 2), recursively call the backtracking algorithm. (go back to step 1)
If the function is called and there are no empty cells, evaluate the board. If everything is ok, you found the solution! If it's not ok, go back.
The evaluation means, check that you have all numbers from 1 to 9 exactly once on every line, every column, and every 3x3 square.
Example of how it might look like:
function back($pos) {
if ($pos >= 9*9) {
if (evaluate()) {
// we found a solution
// do soemthing with it
} else {
return;
}
}
$x = pos / 9;
$y = pos % 9;
if ($m[x][y] != 0) {
// we already have a value assigned for this position
back($pos+1);
return;
}
for ($v = 1; $v <= 9; $v++) {
$m[x][y] = $v;
back($pos+1);
}
$m[x][y] = 0; // clean up tested value before going back
}
back(1)
The above algorithm can be optimized by evaluating lines/columns at every step, instead of just once at the end. If the algorithm tries to place number x, but x is already found on the line/column, then we can just move on to try x+1 since we know x will create an invalid solution.
This question already has answers here:
What in layman's terms is a Recursive Function using PHP
(17 answers)
Closed 8 years ago.
<?php
function factorial_of_a($n)
{
if($n ==0)
{
return 1;
}
else
{
return $n * factorial_of_a( $n - 1 );
}
}
print_r( factorial_of_a(5) );
?>
My doubt is:
return $n * factorial_of_a( $n - 1 ) ;
In this statement - it gives a result of 20 when $n = 5 and $n - 1 = 4. But how come the answer 120 when I run it? Well, 120 is the right answer... I don't understand how it works. I used for-loop instead and it was working fine.
factorial_of_a(5)
Triggering following calls:
5 * factorial_of_a(5 - 1) ->
5 * 4 * factorial_of_a(4 - 1) ->
5 * 4 * 3 * factorial_of_a(3 - 1) ->
5 * 4 * 3 * 2 * factorial_of_a(2 - 1) ->
5 * 4 * 3 * 2 * 1 * factorial_of_a(1 - 1) ->
5 * 4 * 3 * 2 * 1 * 1
So, the answer is 120.
Consider reading recursive function article on wikipedia.
Also, read this related thread: What is a RECURSIVE Function in PHP?
but how come the answer 120 ?
Well, this function will call itself with $n - 1, while $n - 1 is not equals to 0. When it is, then function actually returns result to the program. So it is not returning result instantly, while argument in larger then 0. It is called a "terminate condition" of the recursion.
It will work in this way..
- factorial_of_a(5);
// now read below dry run code from the bottom for proper understanding
// and then read again from top
- if n = 0 ; false // since [n = 5]
- else n*factorial_of_a(n-1); [return 5 * 24]
// here it will get 24 from the last line since 4*6 = 24 and pass
// it to the value of n i.e. **5** here will make it **120**
- if n = 0 ; false [n = 4]
- else n*factorial_of_a(n-1); [return 4 * 6]
// here it will get 6 from the last line since 3*2 = 6 and pass it
// to the value of n i.e. **4** here will make it **24**
- if n = 0 ; false [n = 3]
- else n*factorial_of_a(n-1); [return 3 * 2]
// here it will get 2 from the last line since 2*1 = 2 and pass it
// to the value of n i.e. **3** here will make it **6**
- if n = 0 ; false [n = 2]
- else n*factorial_of_a(n-1); [return 2 * 1]
// here it will get 1 from the last line since 1*1 = 1 and pass it
// to the value of n i.e. **2** here
- if n = 0 ; false [n = 1]
- else n*factorial_of_a(n-1); [return 1 * 1]
// here it will get 1 from the last line and pass it
// to the value of n i.e. **1** here
- if n = 0 ; true // since [n = 0] now it will return 1
- return 1;
To understand this you need to be clear with the concept of recursion.
Recursion means calling a function again and again.
Every recursive function has a terminating case and a recursive case.
Terminating case tells when will the function stop and recursive case calls the function itself again.
In your code the if condition $n == 0 marks the terminating case, i.e. do not do any calculation if a number is equal to 0 and return 1.
The else part is the recursive case [ $n*factorial_of_a($n-1) ]
Now i will explain how it works for $n = 5 :
Since $n is not equal to 0 then else statement is executed which gives 5 *factorial_of_a(4);
Now factorial_of_a(4) is called which gives 4 * factorial_of_a(3);
Now factorial_of_a(3) is called which gives 3 * factorial_of_a(2);
Now factorial_of_a(2) is called which gives 2 * factorial_of_a(1);
Now factorial_of_a(1) is called which gives 1 * factorial_of_a(0);
Now factorial_of_a(0) is called which gives 1
So basically
factorial_of_a(5) = 5 * 4 * 3 * 2 * 1 = 120
Hence the result!
Hope it helped!!
You have to bear in mind that his is a recursion
when you call factorial_of_a(5) it will execute this as
factorial_of_a(5)
// 5 * 24
5 * factorial_of_a(4)
// 4 * 6
4 * factorial_of_a(3)
// 3 * 2
3 * factorial_of_a(2)
// 2 * 1
2 * factorial_of_a(1)
//will return 1 since it is your base condition
1 * factorial_of_a(0)
I am doing this programming challenge which can be found at www.interviewstreet.com (its the first challenge worth 30 points).
When I submitted the solution, I was returned a result which said that the answer was wrong because it only passed 1/11 test cases. However, I feel have tested various cases and do not understand what I am doing wrong. It would be helpful to know what those test cases could be so that I can test my program.
Here is the question (in between the grey lines below):
Quadrant Queries (30 points)
There are N points in the plane. The ith point has coordinates (xi, yi). Perform the following queries:
1) Reflect all points between point i and j both including along the X axis. This query is represented as "X i j"
2) Reflect all points between point i and j both including along the Y axis. This query is represented as "Y i j"
3) Count how many points between point i and j both including lie in each of the 4 quadrants. This query is represented as "C i j"
Input:
The first line contains N, the number of points. N lines follow.
The ith line contains xi and yi separated by a space.
The next line contains Q the number of queries. The next Q lines contain one query each, of one of the above forms.
All indices are 1 indexed.
Output:
Output one line for each query of the type "C i j". The corresponding line contains 4 integers; the number of points having indices in the range [i..j] in the 1st,2nd,3rd and 4th quadrants respectively.
Constraints:
1 <= N <= 100000
1 <= Q <= 100000
You may assume that no point lies on the X or the Y axis.
All (xi,yi) will fit in a 32-bit signed integer
In all queries, 1 <=i <=j <=N
Sample Input:
4
1 1
-1 1
-1 -1
1 -1
5
C 1 4
X 2 4
C 3 4
Y 1 2
C 1 3
Sample Output:
1 1 1 1
1 1 0 0
0 2 0 1
Explanation:
When a query says "X i j", it means that take all the points between indices i and j both including and reflect those points along the X axis. The i and j here have nothing to do with the co-ordinates of the points. They are the indices. i refers to point i and j refers to point j
'C 1 4' asks you to 'Consider the set of points having index in {1,2,3,4}. Amongst those points, how many of them lie in the 1st,2nd,3rd and 4th quads respectively?'
The answer to this is clearly 1 1 1 1.
Next we reflect the points between indices '2 4' along the X axis. So the new coordinates are :
1 1
-1 -1
-1 1
1 1
Now 'C 3 4' is 'Consider the set of points having index in {3,4}. Amongst those points, how many of them lie in the 1st,2nd,3rd and 4th quads respectively?' Point 3 lies in quadrant 2 and point 4 lies in quadrant 1.
So the answer is 1 1 0 0
I'm coding in PHP and the method for testing is with STDIN and STDOUT.
Any ideas on difficult test cases to test my code with? I don't understand why I am failing 10 / 11 test cases.
Also, here is my code if you're interested:
// The global variable that will be changed
$points = array();
/******** Functions ********/
// This function returns the number of points in each quadrant.
function C($beg, $end) {
// $quad_count is a local array and not global as this gets reset for every C operation
$quad_count = array("I" => 0, "II" => 0, "III" => 0, "IV" => 0);
for($i=$beg; $i<$end+1; $i++) {
$quad = checkquad($i);
$quad_count[$quad]++;
}
return $quad_count["I"]." ".$quad_count["II"]." ".$quad_count["III"]." ".$quad_count["IV"];
}
// Reflecting over the x-axis means taking the negative value of y for all given points
function X($beg, $end) {
global $points;
for($i=$beg; $i<$end+1; $i++) {
$points[$i]["y"] = -1*($points[$i]["y"]);
}
}
// Reflecting over the y-axis means taking the negative value of x for all given points
function Y($beg, $end) {
global $points;
for($i=$beg; $i<$end+1; $i++) {
$points[$i]["x"] = -1*($points[$i]["x"]);
}
}
// Determines which quadrant a given point is in
function checkquad($i) {
global $points;
$x = $points[$i]["x"];
$y = $points[$i]["y"];
if ($x > 0) {
if ($y > 0) {
return "I";
} else {
return "IV";
}
} else {
if ($y > 0) {
return "II";
} else {
return "III";
}
}
}
// First, retrieve the number of points that will be provided. Make sure to check constraints.
$no_points = intval(fgets(STDIN));
if ($no_points > 100000) {
fwrite(STDOUT, "The number of points cannot be greater than 100,000!\n");
exit;
}
// Remember the points are 1 indexed so begin key from 1. Store all provided points in array format.
for($i=1; $i<$no_points+1; $i++) {
global $points;
list($x, $y) = explode(" ",fgets(STDIN)); // Get the string returned from the command line and convert to an array
$points[$i]["x"] = intval($x);
$points[$i]["y"] = intval($y);
}
// Retrieve the number of operations that will be provied. Make sure to check constraints.
$no_operations = intval(fgets(STDIN));
if($no_operations > 100000) {
fwrite(STDOUT, "The number of operations cannot be greater than 100,000!\n");
exit;
}
// Retrieve the operations, determine the type and send to the appropriate functions. Make sure i <= j.
for($i=0; $i<$no_operations; $i++) {
$operation = explode(" ",fgets(STDIN));
$type = $operation[0];
if($operation[1] > $operation[2]) {
fwrite(STDOUT, "Point j must be further in the sequence than point i!\n");
exit;
}
switch ($type) {
case "C":
$output[$i] = C($operation[1], $operation[2]);
break;
case "X":
X($operation[1], $operation[2]);
break;
case "Y":
Y($operation[1], $operation[2]);
break;
default:
$output[$i] = "Sorry, but we do not recognize this operation. Please try again!";
}
}
// Print the output as a string
foreach($output as $line) {
fwrite(STDOUT, $line."\n");
}
UPDATE:
I finally found a test case for which my program fails. Now I am trying to determine why. This is a good lesson on testing with large numbers.
10
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
12
C 1 10
X 1 3
C 5 5
Y 2 10
C 10 10
C 1 10
X 1 3
C 5 5
Y 2 10
C 10 10
X 3 7
C 9 9
I am going to test this properly by initializing an error array and determining which operations are causing an issue.
I discovered a test case that failed and understood why. I am posting this answer here so it's clear to everyone.
I placed a constraint on the program so that j must be greater than i, otherwise an error should be returned. I noticed an error with the following test case:
10
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1
C 2 10
The error returned for the operation C. Essentially the program believed that "2" was greater than "10". The reason for this I discovered was the following:
When using fgets(), a string is returned. If you perform string operations such as explode() or substr() on that line, you are converting the numbers in that initial string into a string again. So this means that the 10 becomes "10" and then after string operations becomes "0".
One solution to this is to use the sscanf() function and basically tell the program to expect a number. Example: for "C 2 10" you could use:
$operation_string = fgets(STDIN);
list($type, $begpoint, $endpoint) = sscanf($operation_string, "%s %d %d");
I submitted the new solution using sscanf() and now have 3/11 test cases passed. It did not check any more test cases because the CPU time limit was exceeded. So, now I have to go back and optimize my algorithm.
Back to work! :)
To answer, "What are those test cases?" Try this "solution":
<?php
$postdata = http_build_query(
array(
'log' => file_get_contents('php://stdin')
)
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
file_get_contents('http://myserver/answer.php', false, $context);
?>
On your server:
<?php
$fp = fopen('/tmp/answers.log', 'a');
fputs($fp, $_POST['log']."\n");
fclose($fp);
?>
Edit:
I did that. And came up with this being your main problem (I think):
$operation = explode(" ",fgets(STDIN));
Change that to:
$operation = explode(" ",trim(fgets(STDIN)));
Because otherwise "9" > "41 " due to string comparison. You should make that fix in any place you read a line.
As far as I guess, this solution won't work. Even if you solve the Wrong Answer problem, the solution will time out.
I was able to figure out a way for returning the quadrants count in O(1) time.
But not able to make the reflections in lesser time. :(