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.
I need to convert a really big integer that is represented as a string to a binary string (aka normal integer, but it is always bigger as normal php integer can hold) to efficiently store it in database and have a unique index on it.
The number comes from GMP (gmp_strval()) and may have different lengths, usually about 200-300 "characters" in it, so it never fits into PHP integer. The idea is to convert it into a binary string representing an integer, kind of big integer. Can I do it with PHP?
Sure you can do this.
Remember how to convert a decimal number to binary by hand.
look if the last digit is even (gives a 0) or odd (gives a 1)
subtract the 1, if you get one.
divide by 2. This have to be done digit by digit as in elementary school :-)
repeat this until your decimalnumber become zero.
I wrote a function for this
function strMod2(array $dec)
{
return ((int)end($dec)) % 2;
}
function strDivBy2(array $dec)
{
$res = [];
$carry = 0;
if($dec[0] == '0')
array_shift($dec);
$len = count($dec);
for($i = 0; $i < $len; $i++)
{
$num = $carry*10 + ((int)$dec[$i]);
$carry = $num % 2;
$num -= $carry;
$res[] = $num / 2;
}
return $res;
}
function dec2bin_str($dec)
{
$dec_arr = str_split($dec);
$bin_arr = [];
while(count($dec_arr) > 1 || $dec_arr[0] != 0)
{
array_unshift($bin_arr, strMod2($dec_arr));
$dec_arr = strDivBy2($dec_arr);
}
return implode($bin_arr);
}
You can use it as
echo dec2bin_str('5'); // '101'
echo dec2bin_str('146456131894613465451'); // '1111111000001111100101101000000000000010100001100010101100101101011'
Maybe this can be done faster by using a library for big integers.
Found Math_BigInteger library that can do it:
$a = new Math_BigInteger($intString);
$base256IntString = $a->toBytes();
https://github.com/pear/Math_BigInteger
I am struggling to find/create an algorithm that can determine the pronounceability of random 5 letter combinations.
The closest thing I've found so far is from this 3 year old StackOverflow thread:
Measure the pronounceability of a word?
<?php
// Score: 1
echo pronounceability('namelet') . "\n";
// Score: 0.71428571428571
echo pronounceability('nameoic') . "\n";
function pronounceability($word) {
static $vowels = array
(
'a',
'e',
'i',
'o',
'u',
'y'
);
static $composites = array
(
'mm',
'll',
'th',
'ing'
);
if (!is_string($word)) return false;
// Remove non letters and put in lowercase
$word = preg_replace('/[^a-z]/i', '', $word);
$word = strtolower($word);
// Special case
if ($word == 'a') return 1;
$len = strlen($word);
// Let's not parse an empty string
if ($len == 0) return 0;
$score = 0;
$pos = 0;
while ($pos < $len) {
// Check if is allowed composites
foreach ($composites as $comp) {
$complen = strlen($comp);
if (($pos + $complen) < $len) {
$check = substr($word, $pos, $complen);
if ($check == $comp) {
$score += $complen;
$pos += $complen;
continue 2;
}
}
}
// Is it a vowel? If so, check if previous wasn't a vowel too.
if (in_array($word[$pos], $vowels)) {
if (($pos - 1) >= 0 && !in_array($word[$pos - 1], $vowels)) {
$score += 1;
$pos += 1;
continue;
}
} else { // Not a vowel, check if next one is, or if is end of word
if (($pos + 1) < $len && in_array($word[$pos + 1], $vowels)) {
$score += 2;
$pos += 2;
continue;
} elseif (($pos + 1) == $len) {
$score += 1;
break;
}
}
$pos += 1;
}
return $score / $len;
}
?>
... but it is far from perfect, giving some rather strange false positives:
Using this function, all of the following rate as pronounceable, (above 7/10)
ZTEDA
LLFDA
MMGDA
THHDA
RTHDA
XYHDA
VQIDA
Can someone smarter than me tweek this algorithm perhaps so that:
'MM', 'LL', and 'TH' are only valid when followed or preceeded by a
vowel?
3 or more consonants in a row is a no-no, (except when the first or
last is an 'R' or 'L')
any other refinements you can think of...
(I have done a fair amount of research/googling, and this seems to be the main pronounceability function that everyone has been referencing/using for the last 3 years, so I'm sure an updated, more refined version would be appreciated by the wider community, not just me!).
Based on a suggestion on the linked question to "Use a Markov model on letters"
Use a Markov model (on letters, not words, of course). The probability of a word is a pretty good proxy for ease of pronunciation.
I thought I would try it out and had some success.
My Methodology
I copied a list of real 5-letter words into a file to serve as my dataset (here...um, actually here).
Then I use a Hidden Markov model (based on One-grams, Bi-grams, and Tri-grams) to predict how likely a target word would appear in that dataset.
(Better results could be achieved with some sort of phonetic transcription as one of the steps.)
First, I calculate the probabilities of character sequences in the dataset.
For example, if 'A' occurs 50 times, and there is only 250 characters in the dataset, then 'A' has a 50/250 or .2 probability.
Do the same for the bigrams 'AB', 'AC', ...
Do the same for the trigrams 'ABC', 'ABD', ...
Basically, my score for the word "ABCDE" is composed of:
prob( 'A' )
prob( 'B' )
prob( 'C' )
prob( 'D' )
prob( 'E' )
prob( 'AB' )
prob( 'BC' )
prob( 'CD' )
prob( 'DE' )
prob( 'ABC' )
prob( 'BCD' )
prob( 'CDE' )
You could multiply all of these together to get the estimated probability of the target word appearing in the dataset, (but that is very small).
So instead, we take the logs of each and add them together.
Now we have a score which estimates how likely our target word would appear in the dataset.
My code
I have coded this is C#, and find that a score greater than negative 160 is pretty good.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Pronouncability
{
class Program
{
public static char[] alphabet = new char[]{ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
public static List<string> wordList = loadWordList(); //Dataset of 5-letter words
public static Random rand = new Random();
public const double SCORE_LIMIT = -160.00;
/// <summary>
/// Generates random words, until 100 of them are better than
/// the SCORE_LIMIT based on a statistical score.
/// </summary>
public static void Main(string[] args)
{
Dictionary<Tuple<char, char, char>, int> trigramCounts = new Dictionary<Tuple<char, char, char>, int>();
Dictionary<Tuple<char, char>, int> bigramCounts = new Dictionary<Tuple<char, char>, int>();
Dictionary<char, int> onegramCounts = new Dictionary<char, int>();
calculateProbabilities(onegramCounts, bigramCounts, trigramCounts);
double totalTrigrams = (double)trigramCounts.Values.Sum();
double totalBigrams = (double)bigramCounts.Values.Sum();
double totalOnegrams = (double)onegramCounts.Values.Sum();
SortedList<double, string> randomWordsScores = new SortedList<double, string>();
while( randomWordsScores.Count < 100 )
{
string randStr = getRandomWord();
if (!randomWordsScores.ContainsValue(randStr))
{
double score = getLikelyhood(randStr,trigramCounts, bigramCounts, onegramCounts, totalTrigrams, totalBigrams, totalOnegrams);
if (score > SCORE_LIMIT)
{
randomWordsScores.Add(score, randStr);
}
}
}
//Right now randomWordsScores contains 100 random words which have
//a better score than the SCORE_LIMIT, sorted from worst to best.
}
/// <summary>
/// Generates a random 5-letter word
/// </summary>
public static string getRandomWord()
{
char c0 = (char)rand.Next(65, 90);
char c1 = (char)rand.Next(65, 90);
char c2 = (char)rand.Next(65, 90);
char c3 = (char)rand.Next(65, 90);
char c4 = (char)rand.Next(65, 90);
return "" + c0 + c1 + c2 + c3 + c4;
}
/// <summary>
/// Returns a score for how likely a given word is, based on given trigrams, bigrams, and one-grams
/// </summary>
public static double getLikelyhood(string wordToScore, Dictionary<Tuple<char, char,char>, int> trigramCounts, Dictionary<Tuple<char, char>, int> bigramCounts, Dictionary<char, int> onegramCounts, double totalTrigrams, double totalBigrams, double totalOnegrams)
{
wordToScore = wordToScore.ToUpper();
char[] letters = wordToScore.ToCharArray();
Tuple<char, char>[] bigrams = new Tuple<char, char>[]{
new Tuple<char,char>( wordToScore[0], wordToScore[1] ),
new Tuple<char,char>( wordToScore[1], wordToScore[2] ),
new Tuple<char,char>( wordToScore[2], wordToScore[3] ),
new Tuple<char,char>( wordToScore[3], wordToScore[4] )
};
Tuple<char, char, char>[] trigrams = new Tuple<char, char, char>[]{
new Tuple<char,char,char>( wordToScore[0], wordToScore[1], wordToScore[2] ),
new Tuple<char,char,char>( wordToScore[1], wordToScore[2], wordToScore[3] ),
new Tuple<char,char,char>( wordToScore[2], wordToScore[3], wordToScore[4] ),
};
double score = 0;
foreach (char c in letters)
{
score += Math.Log((((double)onegramCounts[c]) / totalOnegrams));
}
foreach (Tuple<char, char> pair in bigrams)
{
score += Math.Log((((double)bigramCounts[pair]) / totalBigrams));
}
foreach (Tuple<char, char, char> trio in trigrams)
{
score += 5.0*Math.Log((((double)trigramCounts[trio]) / totalTrigrams));
}
return score;
}
/// <summary>
/// Build the probability tables based on the dataset (WordList)
/// </summary>
public static void calculateProbabilities(Dictionary<char, int> onegramCounts, Dictionary<Tuple<char, char>, int> bigramCounts, Dictionary<Tuple<char, char, char>, int> trigramCounts)
{
foreach (char c1 in alphabet)
{
foreach (char c2 in alphabet)
{
foreach( char c3 in alphabet)
{
trigramCounts[new Tuple<char, char, char>(c1, c2, c3)] = 1;
}
}
}
foreach( char c1 in alphabet)
{
foreach( char c2 in alphabet)
{
bigramCounts[ new Tuple<char,char>(c1,c2) ] = 1;
}
}
foreach (char c1 in alphabet)
{
onegramCounts[c1] = 1;
}
foreach (string word in wordList)
{
for (int pos = 0; pos < 3; pos++)
{
trigramCounts[new Tuple<char, char, char>(word[pos], word[pos + 1], word[pos + 2])]++;
}
for (int pos = 0; pos < 4; pos++)
{
bigramCounts[new Tuple<char, char>(word[pos], word[pos + 1])]++;
}
for (int pos = 0; pos < 5; pos++)
{
onegramCounts[word[pos]]++;
}
}
}
/// <summary>
/// Get the dataset (WordList) from file.
/// </summary>
public static List<string> loadWordList()
{
string filePath = "WordList.txt";
string text = File.ReadAllText(filePath);
List<string> result = text.Split(' ').ToList();
return result;
}
}
}
In my example, I scale the trigram probabilities by 5.
I also add one to all of the counts, so we don't multiply by zero.
Final notes
I'm not a php programmer, but the technique is pretty easy to implement.
Play around with some scaling factors, try different datasets, or add in some other checks like what you suggested above.
How about generating a reasonably pronounceable combination from the start? I have done something where I generate a random Soundex code, and work back from that to a (usually) pronounceable original.
If anyone's looking for a way to do this with Node.js, I found a module called pronouncable that seems to implement what Xantix's answer describes.
npm i pronounceable
You can test in without installing anything on RunKit.
I want to calculate Frequency (Monobits) test in PHP:
Description: The focus of the test is
the proportion of zeroes and ones for
the entire sequence. The purpose of
this test is to determine whether that
number of ones and zeros in a sequence
are approximately the same as would be
expected for a truly random sequence.
The test assesses the closeness of the
fraction of ones to ½, that is, the
number of ones and zeroes in a
sequence should be about the same.
I am wondering that do I really need to calculate the 0's and 1's (the bits) or is the following adequate:
$value = 0;
// Loop through all the bytes and sum them up.
for ($a = 0, $length = strlen((binary) $data); $a < $length; $a++)
$value += ord($data[$a]);
// The average should be 127.5.
return (float) $value/$length;
If the above is not the same, then how do I exactly calculate the 0's and 1's?
No, you really need to check all zeroes and ones. For example, take the following binary input:
01111111 01111101 01111110 01111010
. It is clearly (literally) one-sided(8 zeroes, 24 ones, correct result 24/32 = 3/4 = 0.75) and therefore not random. However, your test would compute 125.0 /255 which is close to ½.
Instead, count like this:
function one_proportion($binary) {
$oneCount = 0;
$len = strlen($binary);
for ($i = 0;$i < $len;$i++) {
$intv = ord($binary{$i});
for ($bitp = 0;$bitp < 7;$bitp++) {
$oneCount += ($intv>>$bitp) & 0x1;
}
}
return $oneCount / (8 * $len);
}
Given a list of common words, sorted in order of prevalence of use, is it possible to form word combinations of an arbitrary length (any desired number of words) in order of the 'most common' sequences. For example,if the most common words are 'a, b, c' then for combinations of length two, the following would be generated:
aa
ab
ba
bb
ac
bc
ca
cb
cc
Here is the correct list for length 3:
aaa
aab
aba
abb
baa
bab
bba
bbb
aac
abc
bac
bbc
aca
acb
bca
bcb
acc
bcc
caa
cab
cba
cbb
cac
cbc
cca
ccb
ccc
This is simple to implement for combinations of 2 or 3 words (set length) for any number of elements, but can this be done for arbitrary lengths? I want to implement this in PHP, but pseudocode or even a summary of the algorithm would be much appreciated!
Here's a recursive function that might be what you need. The idea is, when given a length and a letter, to first generate all sequences that are one letter shorter that don't include that letter. Add the new letter to the end and you have the first part of the sequence that involves that letter. Then move the new letter to the left. Cycle through each sequence of letters including the new one to the right.
So if you had gen(5, d)
It would start with
(aaaa)d
(aaab)d
...
(cccc)d
then when it got done with the a-c combinations it would do
(aaa)d(a)
...
(aaa)d(d)
(aab)d(d)
...
(ccc)d(d)
then when it got done with d as the 4th letter it would move it to the 3rd
(aa)d(aa)
etc., etc.
<?php
/**
* Word Combinations (version c) 6/22/2009 1:20:14 PM
*
* Based on pseudocode in answer provided by Erika:
* http://stackoverflow.com/questions/1024471/generating-ordered-weighted-combinations-of-arbitrary-length-in-php/1028356#1028356
* (direct link to Erika's answer)
*
* To see the results of this script, run it:
* http://stage.dustinfineout.com/stackoverflow/20090622/word_combinations_c.php
**/
init_generator();
function init_generator() {
global $words;
$words = array('a','b','c');
generate_all(5);
}
function generate_all($len){
global $words;
for($i = 0; $i < count($words); $i++){
$res = generate($len, $i);
echo join("<br />", $res);
echo("<br/>");
}
}
function generate($len, $max_index = -1){
global $words;
// WHEN max_index IS NEGATIVE, STARTING POSITION
if ($max_index < 0) {
$max_index = count($words) - 1;
}
$list = array();
if ($len <= 0) {
$list[] = "";
return $list;
}
if ($len == 1) {
if ($max_index >= 1) {
$add = generate(1, ($max_index - 1));
foreach ($add as $addit) {
$list[] = $addit;
}
}
$list[] = $words[$max_index];
return $list;
}
if($max_index == 0) {
$list[] = str_repeat($words[$max_index], $len);
return $list;
}
for ($i = 1; $i <= $len; $i++){
$prefixes = generate(($len - $i), ($max_index - 1));
$postfixes = generate(($i - 1), $max_index);
foreach ($prefixes as $pre){
//print "prefix = $pre<br/>";
foreach ($postfixes as $post){
//print "postfix = $post<br/>";
$list[] = ($pre . $words[$max_index] . $post);
}
}
}
return $list;
}
?>
I googled for php permutations and got: http://www.php.happycodings.com/Algorithms/code21.html
I haven't looked into the code if it is good or not. But it seems to do what you want.
I don't know what the term is for what you're trying to calculate, but it's not combinations or even permutations, it's some sort of permutations-with-repetition.
Below I've enclosed some slightly-adapted code from the nearest thing I have lying around that does something like this, a string permutation generator in LPC. For a, b, c it generates
abc
bac
bca
acb
cab
cba
Probably it can be tweaked to enable the repetition behavior you want.
varargs mixed array permutations(mixed array list, int num) {
mixed array out = ({});
foreach(mixed item : permutations(list[1..], num - 1))
for(int i = 0, int j = sizeof(item); i <= j; i++)
out += ({ implode(item[0 .. i - 1] + ({ list[0] }) + item[i..], "") });
if(num < sizeof(list))
out += permutations(list[1..], num);
return out;
}
FWIW, another way of stating your problem is that, for an input of N elements, you want the set of all paths of length N in a fully-connected, self-connected graph with the input elements as nodes.
I'm assuming that when saying it's easy for fixed length, you're using m nested loops, where m is the lenght of the sequence (2 and 3 in your examples).
You could use recursion like this:
Your words are numbered 0, 1, .. n, you need to generate all sequences of length m:
generate all sequences of length m:
{
start with 0, and generate all sequences of length m-1
start with 1, and generate all sequences of length m-1
...
start with n, and generate all sequences of length m-1
}
generate all sequences of length 0
{
// nothing to do
}
How to implement this? Well, in each call you can push one more element to the end of the array, and when you hit the end of the recursion, print out array's contents:
// m is remaining length of sequence, elements is array with numbers so far
generate(m, elements)
{
if (m == 0)
{
for j = 0 to elements.length print(words[j]);
}
else
{
for i = 0 to n - 1
{
generate(m-1, elements.push(i));
}
}
}
And finally, call it like this: generate(6, array())