Get factors of a number - php

I need to get two factors ( x, y ) of a given number ( n ) such that:
x * y <= n
x * y should be as close to n as possible
x and y should be as close to each other as possible.
Examples:
n = 16 => x = 4, y = 4
n = 17 => x = 4, y = 4
n = 18 => x = 6, y = 3
n = 20 => x = 5, y = 4
Any language will do but preferably php.
EDIT -- CLARIFICATION
I want to create a rectangle, x units wide * y units tall such that its area is as close to n as possible. x and y must be integers. If n is a prime number then factors of n - 1 are acceptable.

Your specifications weren't quite exact enough. You stated that you wanted factors, yet in your test case 4 is not a factor of 17
The following pseudo code works prioritizing that one factor is exact
for i in range(ceiling(sqrt(n)), 1){
if ( n modulo i ) == 0 {
x = i
y = round(n/i)
}
}
Where as a simple sqrt statement will work for ensuring that the numbers are as close together as possible, but doesn't guarantee that they are factors.
x = y = round( sqrt(n) )

You need to decide how important your three rules are.
Possibility 1: If x * y being as close to n as possible is true then n=17 => 1,17 not 4,4. In this case you want factorisation and there are lots of ways to do it, but code like this is simple:
for(i = floor(sqrt(n)) .. 1) {
if n % i ==0 {
x = i;
y = n/x;
break;
}
}
Possibility 2: If being close to each other is more important you'd expect n=18=>4,4 rather than 3,6, and this code would work. This however is not factors.
x=floor(sqrt(n))
y=floor(n/x)
The problem as written is unsolvable without a clearer specification.
EDIT ------------
Now the spec has been edited it is now defined, but you need to do Possibility 1, see if the result is prime (1 is one of the values) and then if it is repeat doing Possibility 2. However, I doubt this is what whichever teacher wrote this as homework intended.

$num = ...; // some number
if (is_prime($num)) // implement the is_prime() function yourself
--$num; // Subtract to get an even number, which is not a prime
$candidates = array(); // Numbers that may fit.
$top_search = $num / 2; // Limits the useless search for candidates
for($i=1; $i < $top_search; ++$i)
{
if ($num % $i == 0)
$candidates[$i] = $num / $i;
}
// Now, check the array in the middle

An idea from me (more pseudo then php)
$root = sqrt($inputNumber);
$x = floor($root);
$y = floor($root);
if(($root - $x) > 0.5) $y++;

I'd have all the factors written to an array using the following code.
#Application lists all factors/divisors for a number.
targetNumber=input('What number do you want the factors for?\n> ')
factors=[]
for i in range(1,targetNumber):
if targetNumber%i==0:
factors.append(i)
elif targetNumber/i==1:
factors.append(targetNumber)
break
print factors
Then I'd loop through the array to check which ones can actually be used. For more on this algorithm, check out http://pyfon.blogspot.com.au/2012/09/list-factors-of-number-in-python.html

Here is a PHP function that prioritize the two 'factors' being close to each other over having exact factors:
function weird_factors($ori) {
$sq = intval(sqrt($ori));
$start = $sq - 10;
$end = $sq + 10;
$n = 0;
for ($s = $start; $s <= $end; $s++) {
for ($t = $start; $t <= $end; $t++) {
$st = $s * $t;
if ($st <= $ori and $st > $n) {
$n = $st;
$ns = $s;
$nt = $t;
}
}
}
return array($ns, $nt);
}

Write a program to find factor of any number
<?php
if(isset($_POST['sub']))
{ $j=0;
$factor=array();
$num=$_POST['nm1'];
for($i=1;$i<=$num;$i++)
{
if($num%$i==0)
{
$j++;
$factor[$j]=$i;
}
}
}
?>
<table>
<form name="frm" method="post" action="">
<tr> <td>Number:</td> <td><input type="text" name="nm1" /></td> </tr>
<tr><td></td><td><input type="submit" name="sub" /></td>
<td><center><span>
<?php
if(isset($_POST['sub']))
{
echo "Factors are :";for($i=1;$i<=count($factor);$i++)
{ echo $factor[$i].",";
}
}
?>
</span></center></td></tr>
</form>
</table>

Related

Algorithm to find positive and negative integer square roots (without given boundaries)

I've been practicing a lot of algorithms recently for an interview. I was wondering if there was another way to solve this problem. I wrote it in a way where I only increment it positively, because I know from basic math that two negatives multiplied by each other would result to a positive number, so I would just have to make the integer that would satisfy the condition to negative.
Is there a way to write this elegantly where you didn't have the knowledge of multiplying two negative numbers result to a positive?
<?php
# Z = {integers}
# B = {x:x, x is an element of Z, x^2 + 1 = 10}
$numNotFound = true;
$x = 0;
$b = [];
while ($numNotFound) {
if ($x*$x + 1 == 10) {
array_push($b, $x, $x*-1);
$numNotFound = false;
}
$x++;
}
echo json_encode($b); #[3, -3]
Updated
This solution does not use the fact that -1 * -1 = 1. It will output the first number found as the first element in the array. If x=-3 then [-3,3] or if x=3 [3,-3].
$numNotFound = TRUE;
$x = 0;
$b = [];
Do{
if ((pow($x, 2) + 1) === 10) {
array_push($b, $x, 0 - $x);
$numNotFound = FALSE;
}
$x++;
}while($numNotFound);
echo json_encode($b); //[3, -3]

Generate random number in range [M....N] with mean X

Generating a random number in the range [M..N] is easy enough. I however would like to generate a series of random numbers in that range with mean X (M < X < N).
For example, assume the following:
M = 10000
N = 1000000
X = 20000
I would like to generate (a large amount of) random numbers such that the entire range [M..N] is covered, but in this case numbers closer to N should become exceedingly more rare. Numbers closer to M should be more common to ensure that the mean converges to X.
The intended target language is PHP, but this is not a language question per se.
There are many ways to accomplish this, and it would differ very much depending on your demands on precision. The following code uses the 68-95-99.7 rule, based on the normal distribution, with a standard deviation of 15% of the mean.
It does not:
ensure exact precision. If you need this you have to calculate the real mean and compensate for the missing amount.
created a true normal distributed curve dynamically, as all the three chunks (68-95-99.7) are considered equal within their groups.
It does however give you a start:
<?php
$mean = (int)$_GET['mean']; // The mean you want
$amnt = (int)$_GET['amnt']; // The amount of integers to generate
$sd = $mean * 0.15;
$numbers = array();
for($i=1;$i<$amnt;$i++)
{
$n = mt_rand(($mean-$sd), ($mean+$sd));
$r = mt_rand(10,1000)/10; // For decimal counting
if($r>68)
{
if(2==mt_rand(1,2)) // Coin flip, should it add or subtract?
{
$n = $n+$sd;
}
else
{
$n = $n-$sd;
}
}
if($r>95)
{
if(2==mt_rand(1,2))
{
$n = $n+$sd;
}
else
{
$n = $n-$sd;
}
}
if($r>99.7)
{
if(2==mt_rand(1,2))
{
$n = $n+$sd;
}
else
{
$n = $n-$sd;
}
}
$numbers[] = $n;
}
arsort($numbers);
print_r($numbers);
// Echo real mean to see how far off you get. Typically within 1%
/*
$sum = 0;
foreach($numbers as $val)
{
$sum = $sum + $val;
}
echo $rmean = $sum/$amnt;
*/
?>
Hope it helps!

How to generate random numbers to produce a non-standard distributionin PHP

I've searched through a number of similar questions, but unfortunately I haven't been able to find an answer to this problem. I hope someone can point me in the right direction.
I need to come up with a PHP function which will produce a random number within a set range and mean. The range, in my case, will always be 1 to 100. The mean could be anything within the range.
For example...
r = f(x)
where...
r = the resulting random number
x = the mean
...running this function in a loop should produce random values where the average of the resulting values should be very close to x. (The more times we loop the closer we get to x)
Running the function in a loop, assuming x = 10, should produce a curve similar to this:
+
+ +
+ +
+ +
+ +
Where the curve starts at 1, peeks at 10, and ends at 100.
Unfortunately, I'm not well versed in statistics. Perhaps someone can help me word this problem correctly to find a solution?
interesting question. I'll sum it up:
We need a funcion f(x)
f returns an integer
if we run f a million times the average of the integer is x(or very close at least)
I am sure there are several approaches, but this uses the binomial distribution: http://en.wikipedia.org/wiki/Binomial_distribution
Here is the code:
function f($x){
$min = 0;
$max = 100;
$curve = 1.1;
$mean = $x;
$precision = 5; //higher is more precise but slower
$dist = array();
$lastval = $precision;
$belowsize = $mean-$min;
$abovesize = $max-$mean;
$belowfactor = pow(pow($curve,50),1/$belowsize);
$left = 0;
for($i = $min; $i< $mean; $i++){
$dist[$i] = round($lastval*$belowfactor);
$lastval = $lastval*$belowfactor;
$left += $dist[$i];
}
$dist[$mean] = round($lastval*$belowfactor);
$abovefactor = pow($left,1/$abovesize);
for($i = $mean+1; $i <= $max; $i++){
$dist[$i] = round($left-$left/$abovefactor);
$left = $left/$abovefactor;
}
$map = array();
foreach ($dist as $int => $quantity) {
for ($x = 0; $x < $quantity; $x++) {
$map[] = $int;
}
}
shuffle($map);
return current($map);
}
You can test it out like this(worked for me):
$results = array();
for($i = 0;$i<100;$i++){
$results[] = f(20);
}
$average = array_sum($results) / count($results);
echo $average;
It gives a distribution curve that looks like this:
I'm not sure if I got what you mean, even if I didn't this is still a pretty neat snippet:
<?php
function array_avg($array) { // Returns the average (mean) of the numbers in an array
return array_sum($array)/count($array);
}
function randomFromMean($x, $min = 1, $max = 100, $leniency = 3) {
/*
$x The number that you want to get close to
$min The minimum number in the range
$max Self-explanatory
$leniency How far off of $x can the result be
*/
$res = [mt_rand($min,$max)];
while (true) {
$res_avg = array_avg($res);
if ($res_avg >= ($x - $leniency) && $res_avg <= ($x + $leniency)) {
return $res;
break;
}
else if ($res_avg > $x && $res_avg < $max) {
array_push($res,mt_rand($min, $x));
}
else if ($res_avg > $min && $res_avg < $x) {
array_push($res, mt_rand($x,$max));
}
}
}
$res = randomFromMean(22); // This function returns an array of random numbers that have a mean close to the first param.
?>
If you then var_dump($res), You get something like this:
array (size=4)
0 => int 18
1 => int 54
2 => int 22
3 => int 4
EDIT: Using a low value for $leniency (like 1 or 2) will result in huge arrays, since testing, I recommend a leniency of around 3.

Finding next fibonacci number

I need to find a (the next) fibonacci number given a integer N. So let's say I have n = 13 and I need to output the next fibonacci number which is 21 but how do I do this? How can I find the previous number that summed up to form it?
I mean I could easily come up with a for/while loop that returns the fibonacci sequence but how can I find the next number by being given the previous one.
<?php
$n = 13;
while($n < 1000) {
$n = $x + $y;
echo($n."<br />");
$x = $y;
$y = $n;
}
?>
You can use Binet's Formula:
n -n
F(n) = phi - (-phi)
---------------
sqrt(5)
where phi is the golden ratio (( 1 + sqrt(5) ) / 2) ~= 1.61803...
This lets you determine exactly the n-th term of the sequence.
Using a loop you could store the values in an array that could stop immediately one key after finding the selected number in the previous keys value.
function getFib($n) {
$fib = array($n+1); // array to num + 1
$fib[0] = 0; $fib[1] = 1; // set initial array keys
$i;
for ($i=2;$i<=$n+1;$i++) {
$fib[$i] = $fib[$i-1]+$fib[$i-2];
if ($fib[$i] > $n) { // check if key > num
return $fib[$i];
}
}
if ($fib[$i-1] < $n) { // check if key < num
return $fib[$i-1] + $n;
}
if ($fib[$i] = $n-1) { // check if key = num
return $fib[$i-1] + $fib[$i-2];
}
if ($fib[$i-1] = 1) { // check if num = 1
return $n + $n;
}
}
$num = 13;
echo "next fibonacci number = " . getFib($num);
Please note that I haven't tested this out and the code could be optimized, so before downvoting consider this serves only as a concept to the question asked.
You can do it in 1 step:
phi = (1+sqrt(5))/2
next = round(current*phi)
(Where round is a function that returns the closest integer; basically equivalent to floor(x+0.5))
For example, if your current number is 13: 13 * phi = 21.034441853748632, which rounds to 21.

PHP code is taking very much time in executing when handling large number

This is a simple program to find prime numbers which check for the division of a number at later stage.
I tried to short it by initially taking the integer square root of the number to break down the complexity. But still it is taking very much time in executing the script. What other changes I can implement in my code to decrease the execution time( I already set the max execution time to 5 min)
<?php
error_reporting(E_ALL);
$num = 600851475143;
//$sqrt_num = (int)sqrt($num);
for( $j = 2; $j <= $num; $j++ )
{
for( $k = 2; $k < $j; $k++ )
{
if( $j % $k == 0 )
{
break;
}
}
if( $k == $j )
{
//echo "Prime Number : ", $j, "<br>";
if( $num % $j == 0 )
{
echo "Prime number : ", $j, "<br>";
}
}
}
EDIT Just commented the line for sqrt as this seems to be in correct..but still the loop is taking much time.
One way to improve execution time of your code would be this:
$num = 1000;
for($j = 2; $j <= $num; $j++)
{
$cond = sqrt($j);
for($k = 2; $k <= $cond; $k++)
{
if($j % $k == 0)
{
break;
}
}
if($k > $cond)
{
echo 'Prime number: ' . $j . '<br>';
}
}
But there is no need to calculate prime numbers from the begining each time. You can remember every 30 seconds or so where you were, save the result to a database, file, or an array, and then restart the script, which should the continue from where it stopped.
The best way to reduce this code execution time is by removing it.
It's unnecessary to calculate every prime number each time you run this- they are not going to be changing any time soon.
Run it once, write it to a file or database and use that when you need it.
I'd personally put it in an array for later use.
Here's the basic algorithm for factoring by trial division; I don't know PHP, so I'll just give pseudocode:
function factors(n)
f, fs := 2, []
while f * f <= n
while n % f == 0
append f to fs
n := n / f
f := f + 1
if n > 1 append n to fs
return fs
There are better ways than that to find the factors of a number, but even that simple method should be sufficient for the Project Euler problem you are trying to solve; you should have a soluion in less than a second. When you're ready for more programming with prime numbers, I modestly recommend this essay at my blog.

Categories