Exponential function algorithm - php

I need to implement a function that interpolates an exponential curve from three points, but I'm not sure how to do it.
I have a graph that has the Y axis as percentage, 0 to 100% and X as 0 to 10.
The only points that I know are (50,7), (100,10) and (0,0).
I know I can create an array that has the percentages and values and loop through it, but this does not feel like the "right" way to do it. Is there a more direct algorithm?

I would use the formula :
partial : total = % : 100
partial (the value) = (total * %) / 100
Code
<?php
$points = array("8%,67%","36%,74%","73%,13%");
function return_value($percentage,$total) {
$value = ($total * $percentage) / 100.0;
return $value;
}
function evaluate_points($points) {
$max_x = 100.0; // As float value
$max_y = 10.0; // As float value
for ($point = 0; $point < count($points); $point++) {
//Replace the % sign
$points[$point] = str_replace("%", "", $points[$point]);
$point_percentages = explode(",", $points[$point]);
$x_percentage = $point_percentages[0];
$y_percentage = $point_percentages[1];
echo("The value for x is : ".return_value($x_percentage,$max_x) ."<br>");
echo("The value for y is : ".return_value($y_percentage,$max_y). "<br><br>");
}
}
evaluate_points($points);
?>
Output

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]

Round up decimal number for specific decimal places in PHP

I want to round up my variable if it's decimal larger than .3 and if it's lower or equal it will round down, for example if i have 1.34 it will round up to 2, if i have 1.29 it will round down to 1, and if i have 1.3 it will round down to 1. I don't know how to do this precisely, right now i'm using the round basic function like this:
$weight = $weight/1000;
if($weight < 1) $weight = 1;
else $weight = round($weight, 0, PHP_ROUND_HALF_DOWN);
If you manipulate the numbers a bit, you can figure out if the decimals are .3 or higher. You achieve this by flooring the value, and subtract that from the original value. Check if the result of that, multiplied by 10, is greater than 3. If it is, you've got something above x.3.
$number = 1.31;
$int = floor($number);
$float = $number-$int;
if ($float*10 > 3.1)
$result = ceil($number);
else
$result = $int;
echo $result; // 2
Live demo
I made you a little hack, here's the code
$weight = 5088;
$weight = $weight/1000;
if($weight < 1) {
$weight = 1;
} else {
// I get the last number (I treat the $weight as a string here)
$last_number = substr($weight, -1, 1);
// Then I get the precision (floating numbers)
$precision = strlen(substr(strrchr($weight, "."), 1));
// Then I convert it to a string so I can use some helpful string functions
$weight_str = (string) $weight;
// If the last number is less then 3
if ($last_number > 3)
// I change it to 9 I could just change it to 5 and it would work
// because round will round up if then number is 5 or greater
$weight_str[strlen($weight_str) -1] = 9;
}
}
// Then the round will round up if it's 9 or round down if it's 3 or less
$weight = round($weight_str, $precision);
echo $weight;
Maybe something like this function?
function roundImproved($value, $decimalBreakPart = 0.3) {
$whole = floor($value);
$decimal = $value - $whole;
$decimalPartLen = strlen($decimal) - 2;
return (number_format($decimal, $decimalPartLen) <= number_format($decimalBreakPart, $decimalPartLen) ? $whole : ceil($value));
}
Proof:
http://sandbox.onlinephpfunctions.com/code/d75858f175dd819de069a8a05611ac9e7053f07a
You can specify "break part" if you want.

How to raise an float number to big integer?

I tried to do something like that:
$total = 0;
for ($j = 0; $j < 1000; $j++) {
$x = $j / 1000;
$total += pow($x, 1500) * pow((1 - $x), 500);
}
$total is 0.
PHP can't work with too small float values. What can I do? Which libraries can I use?
The function
f(x) = x^1500 * (1-x)^500
has (logarithmic) derivative
f'(x)/f(x)=d/dx log(f(x))
= 1500/x - 500/(1-x)
which is zero for
x0 = 3/4
having the maximum value of
f(3/4) = 3^1500/2^4000 = exp(-1124.6702892376163)
= 10^(-488.4381005764309)
= 3.646694848749686e-489
Using that as reference value, one can now sum up
f(i/1000)/f(3/4)=exp(1500*log(i/1000)+500*log(1-i/1000)+1124.6702892376163)
giving a sum of 24.26257515625789 so that the desired result is
24.26257515625789*f(3/4)=8.847820783972776e-488
A practical way to compute such a sum would be to compute the list of logarithms (more python than PHP, look up the corresponding array operations)
logf = [ log(f(i/1000.0)) for i=1..999 ]
using the transformed logarithm of f, log(f(x))=1500*log(x)+500*log(1-x).
Then compute maxlogf = max(logf), extract the number N=floor(maxlogf/log(10)) of the decimal power and compute the sum as
sumfred = sum([ exp( logfx - N*log(10) ) for logfx in logf ])
so that the final result is sumfred*10^N.

PHP String to Int for MySQL Unique ID

I would like to convert a 17 digit unique ID retrieved as a string from my MYSQL database to a number. I use the int to do so. However I get a zero at the end:
$num = 96435171263250434;
(int)$num --> 96435171263250430
I've checked I am running a 64 bit system. I get the following:
php -r 'echo PHP_INT_MAX;'
9223372036854775807
How do I fix this issue???
You cannot exceed PHP_INT_MAX
$num = "96435171263250434";
$x = (float) $num; // This should hold it but it's a float
$maxIntMult = 0;
$maxIntMult = intval($x / PHP_INT_MAX);
$remainder = $x - $maxIntMult * PHP_INT_MAX;
echo PHP_INT_MAX . " x " .$maxIntMult. " + " . $remainder; // function of two integer if you can't work with floats and you can make something of this
You can try to make use of the fact that ids don't have negative values, effectively doubling your range.
$num = PHP_INT_MAX + 50;
$x = (float) $num;
$intX = $num - PHP_INT_MAX;
echo $intX; // Shows 50 with the '0' being -PHP_INT_MAX
function getIdWithNonZeroOffset($stringId)
{
$x = (float) $stringId;
$intX = $x - PHP_INT_MAX;
return $intX;
}
function getStringFromNonZeroOfssetId($id)
{
return (string) ($id + PHP_INT_MAX);
}
echo getIdWithNonZeroOffset((string)(PHP_INT_MAX + 200)); // Gives 200 (store this in int column)
echo getStringFromNonZeroOfssetId(200); // Gives "2147483847" (my max int is "2147483647")

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.

Categories