convert number to word in php not working - php

Please note, the following PHP code converts amount in number to amount in words. This works fine for integer like (ex. 5250) and when it with decimal it gives wrong results.
Ex: for 450 = four hundred fifty only.
Ex: for 450.5 = four thousand five hundred five (which is wrong) and it should be four hundred fifty and fifty paisa only.
I have checked in the web analysed but unable to rectify the code. Can any body suggest /correct the code please?
<?php
function inr($number){
//A function to convert numbers into words.
$words = array(
'0'=> '' ,'1'=> 'one' ,'2'=> 'two' ,'3' => 'three','4' => 'four','5' => 'five',
'6' => 'six','7' => 'seven','8' => 'eight','9' => 'nine','10' => 'ten',
'11' => 'eleven','12' => 'twelve','13' => 'thirteen','14' => 'fouteen','15' => 'fifteen',
'16' => 'sixteen','17' => 'seventeen','18' => 'eighteen','19' => 'nineteen','20' => 'twenty',
'30' => 'thirty','40' => 'fourty','50' => 'fifty','60' => 'sixty','70' => 'seventy',
'80' => 'eighty','90' => 'ninty');
//First find the length of the number
$number_length = strlen($number);
//Initialize an empty array
$number_array = array(0,0,0,0,0,0,0,0,0);
$received_number_array = array();
//Store all received numbers into an array
for($i=0;$i<$number_length;$i++){ $received_number_array[$i] = substr($number,$i,1); }
//Populate the empty array with the numbers received - most critical operation
for($i=9-$number_length,$j=0;$i<9;$i++,$j++){ $number_array[$i] = $received_number_array[$j]; }
$number_to_words_string = "";
//Finding out whether it is teen ? and then multiplying by 10, example 17 is seventeen, so if 1 is preceeded with 7 multiply 1 by 10 and add 7 to it.
for($i=0,$j=1;$i<9;$i++,$j++){
if($i==0 || $i==2 || $i==4 || $i==7){
if($number_array[$i]=="1"){
$number_array[$j] = 10+$number_array[$j];
$number_array[$i] = 0;
}
}
}
$value = "";
for($i=0;$i<9;$i++){
if($i==0 || $i==2 || $i==4 || $i==7){ $value = $number_array[$i]*10; }
else{ $value = $number_array[$i]; }
if($value!=0){ $number_to_words_string.= $words["$value"]." "; }
if($i==1 && $value!=0){ $number_to_words_string.= "Crores "; }
if($i==3 && $value!=0){ $number_to_words_string.= "Lakhs "; }
if($i==5 && $value!=0){ $number_to_words_string.= "Thousand "; }
if($i==6 && $value!=0){ $number_to_words_string.= "Hundred "; }
}
if($number_length>9){ $number_to_words_string = "Sorry This does not support more than 99 Crores"; }
return ucwords(strtolower("Rupees ".$number_to_words_string)." Only.");
}
?>

you need to explode values after decimal point like
$numberarr = explode('.',$number);
$number = $numberarr[0];
$number_length = strlen($number);
//output Rupees Four Hundred Fifty Only.
also need more work on $numberarr[1] //we get after (.) values

why you have written $my_fig=inr(450.5) what is inr() function ?
try using intval() replacing inr()..

The problem starts here:
$number_length = strlen($number);
Consider the following numbers:
1234
12.3
The two numbers are clearly different orders of magnitude, but since your code centers around the string length, it treats the numbers as though they were the same order of magnitude. Because of this bad assumption, the answer returned is incorrect.
To fix the problem, recognize that a different system is used to create word values for the numbers before the decimals than after. For this reason, you need to first split the number at the decimal and process the two parts separately.
$integer_value = floor($number);
if (strstr($number, '.')) {
$decimal_value = (int)substr($number, strpos($number, '.'));
// Convert $decimal_value to its word value
}
There are well-tested libraries that will do all of this for you, so unless this is just a learning exercise I suggest that you make use of one of those.

Related

BC math string into scientific notation

i use bc math (http://php.net/manual/en/book.bc.php).
the value is, e.g.,
$value = "0.0000000000000000000001111111111111111111112";
how can i transform it into scientific notation. it should be like this:
$value = "1.111111111111111111112E-22";
i tried amongst others
sprintf("%E",$value) or a (float)
but the result are only
1.111111E-22 (sprintf)
That are not so many significant figures as it should be :(
Count how many zeroes there are.
Note that because you are using big numbers, you have to work on them as strings. So...
if( preg_match("/^0\.0*/",$value,$m)) {
$zeroes = strlen($m[0]);
$value = substr($value,$zeroes,1)
.rtrim(".".substr($value,$zeroes+1),"0.")
."E-".($zeroes-1);
}
elseif( preg_match("/(\d+)(?:\.(\d+))?/",$value,$m)) {
$zeroes = strlen($m[1]);
$value = substr($value,0,1)
.rtrim(".".substr($m[1],1).$m[2],"0.")
."E+".($zeroes-1);
}
// else 1 <= number < 10, so no transformation needed
Test cases:
1000000 => 1E+6
1234.5678 => 1.2345678E+3
0.9 => 9E-1
0.123 => 1.23E-1
0.00000011111122222 => 1.1111122222E-7
You can do $float_value = (float)$value; and get 1.1111111111111E-22 but beyond that the float cannot offer more precision so it can't show that 2 at the end.

Printing all permutations of strings that can be formed from phone number

I'm trying to print the possible words that can be formed from a phone number in php. My general strategy is to map each digit to an array of possible characters. I then iterate through each number, recursively calling the function to iterate over each possible character.
Here's what my code looks like so far, but it's not working out just yet. Any syntax corrections I can make to get it to work?
$pad = array(
array('0'), array('1'), array('abc'), array('def'), array('ghi'),
array('jkl'), array('mno'), array('pqr'), array('stuv'), array('wxyz')
);
function convertNumberToAlpha($number, $next, $alpha){
global $pad;
for($i =0; $i<count($pad[$number[$next]][0]); $i++){
$alpha[$next] = $pad[$next][0][$i];
if($i<strlen($number) -1){
convertNumberToAlpha($number, $next++, $alpha);
}else{
print_r($alpha);
}
}
}
$alpha = array();
convertNumberToAlpha('22', 0, $alpha);
How is this going to be used? This is not a job for a simple recursive algorithm such as what you have suggested, nor even an iterative approach. An average 10-digit number will yield 59,049 (3^10) possibilities, each of which will have to be evaluated against a dictionary if you want to determine actual words.
Many times, the best approach to this is to pre-compile a dictionary which maps 10-digit numbers to various words. Then, your look-up is a constant O(1) algorithm, just selecting by a 10 digit number which is mapped to an array of possible words.
In fact, pre-compiled dictionaries were the way that T9 worked, mapping dictionaries to trees with logarithmic look-up functions.
The following code should do it. Fairly straight forward: it uses recursion, each level processes one character of input, a copy of current combination is built/passed at each recursive call, recursion stops at the level where last character of input is processed.
function alphaGenerator($input, &$output, $current = "") {
static $lookup = array(
1 => "1", 2 => "abc", 3 => "def",
4 => "ghi", 5 => "jkl", 6 => "mno",
7 => "pqrs", 8 => "tuv", 9 => "wxyz",
0 => "0"
);
$digit = substr($input, 0, 1); // e.g. "4"
$other = substr($input, 1); // e.g. "3556"
$chars = str_split($lookup[$digit], 1); // e.g. "ghi"
foreach ($chars as $char) { // e.g. g, h, i
if ($other === false) { // base case
$output[] = $current . $char;
} else { // recursive case
alphaGenerator($other, $output, $current . $char);
}
}
}
$output = array();
alphaGenerator("43556", $output);
var_dump($output);
Output:
array(243) {
[0]=>string(5) "gdjjm"
[1]=>string(5) "gdjjn"
...
[133]=>string(5) "helln"
[134]=>string(5) "hello"
[135]=>string(5) "hfjjm"
...
[241]=>string(5) "iflln"
[242]=>string(5) "ifllo"
}
You should read Norvigs article on writing a spellchecker in Python http://norvig.com/spell-correct.html . Although its a spellchecker and in python not php, it is the same concept around finding words with possible variations, might give u some good ideas.

Generate a random number from a given set of numbers and chances

I have a list of numbers like
$list = array(1,5,19,23,59,51,24)
in actual code this is generated from database, so this array will hold up to 500 numbers that are different from each other.
each of these numbers in the database has a probability of occurring recorded. So i have a data from previous executions to generate random numbers from 1 to 500 and recorded the probabilities of each number generated for like 1000 times.
Now having list of numbers and probabilities for each number i want to write a function that will generate a random number from these 500 numbers based on their probabilities.
For example:
number 1 has a chance of: 0.00123 //0.123%
number 6 has a chance of: 0.0421 //4.21%
number 11 has a chance of: 0.0133 //1.33%
so variable $finallist will look something like this:
$finallist[1] = 0.00123;
$finallist[6] = 0.0421;
$finallist[11] = 0.0133;
Now if i run my function and pass in $finallist as a parameter i want to retrieve a random number between 1 and 6 but number 6 will have higher possibility of coming out than 1 and 11 will have higher possibility to come out than 1.
I have some functions written that deal with returning the random number based on its chance but it only takes 1 value as a parameter.
private function randomWithProbability($chance, $num, $range = false)
{
/* first generate a number 0 and 1 and see if that number is in the range of chance */
$rand = $this->getRandomFloatValue(0, 1);
if ($rand <= $chance)
{
/* the number should be returned */
return $num;
}
else
{
/* otherwise return a random number */
if ($range !== false)
{
/* make sure that this number is not same as the number for which we specified the chance */
$rand = mt_rand(1, $range);
while ($rand == $num)
{
$rand = mt_rand(1, $range);
}
return $rand;
}
}
}
if anyone knows a solution/algorithm to do this or if there is anything built in to PHP would be a big help. Thank you so much.
The basic algorithm you're looking for:
add all the probabilities together and determine the maximum
pick a random number between 0 and 1 and multiply it by the max
find the entry that corresponds with that value
Example code:
<?php
// create some weighted sample data (id => weight)
$samples = array(
'a' => 0.001,
'b' => 0.004,
'c' => 0.006,
'd' => 0.05,
'e' => 0.01,
'f' => 0.015,
'g' => 0.1
);
class Accumulator {
function __construct($samples) {
// accumulate all samples into a cumulative amount (a running total)
$this->acc = array();
$this->ids = array();
$this->max = 0;
foreach($samples as $k=>$v) {
$this->max += $v;
array_push($this->acc, $this->max);
array_push($this->ids, $k);
}
}
function pick() {
// selects a random number between 0 and 1, increasing the multiple here increases the granularity
// and randomness; it should probably at least match the precision of the sample data (in this case 3 decimal digits)
$random = mt_rand(0,1000)/1000 * $this->max;
for($i=0; $i < count($this->acc); $i++) {
// looks through the values until we find our random number, this is our seletion
if( $this->acc[$i] >= $random ) {
return $this->ids[$i];
}
}
throw new Exception('this is mathematically impossible?');
}
private $max; // the highest accumulated number
private $acc; // the accumulated totals for random selection
private $ids; // a list of the associated ids
}
$acc = new Accumulator($samples);
// create a results object to test our random generator
$results = array_fill_keys(array_keys($samples), 0);
// now select some data and test the results
print "picking 10000 random numbers...\n";
for($i=0; $i < 10000; $i++) {
$results[ $acc->pick() ]++;
}
// now show what we found out
foreach($results as $k=>$v) {
print "$k picked $v times\n";
}
The results:
> php.exe rand.php
picking 10000 random numbers...
a picked 52 times
b picked 198 times
c picked 378 times
d picked 2655 times
e picked 543 times
f picked 761 times
g picked 5413 times
Running the same code with this sample:
// samples with even weight
$samples = array(
'a' => 0.1,
'b' => 0.1,
'c' => 0.1,
'd' => 0.1
);
Produces these results:
> php.exe rand.php
picking 10000 random numbers...
a picked 2520 times
b picked 2585 times
c picked 2511 times
d picked 2384 times

php abbreviating numbers with K/M

The function below finds the number, rounds it off and puts a K or M on the end of it
IE: 25000 becomes 25K
function abbr_no($number) {
$number = preg_replace('/[^0-9]/', '', $number);
$numbers = array('', 'K', 'M');
if ($number == 0) {
return('n/a');
} else {
return (round($number/pow(10000, ($i = floor(log($number, 10000)))), 0) . $numbers[$i]);
}
}
and so it basically does what I want, but as is for a number like 389345 it rounds it off and spits out 39K (as it should) however I would like the result to be 398K (3 digit number)
Now in the last return line:
0) . $numbers[$i]);
if I change the 0 to a 1 the result becomes 39.8K but again I don't want the decimal point so I am currently stuck and have hit a brickwall
As always all help is appreciated and thank you in advance.
This allows you to convert on all sorts of scales,
function humanize($val, $postfix)
{
foreach ($postfix as $p=>$div) {
$t=round($val/$div) . $p;
if (strlen($t)<(3+strlen($p))) {
break;
}
}
return trim($t);
}
e.g.
$postfix=array(''=>1, 'K'=>1000,'M'=>1000000,'B'=>1000000000);
To answer the original question,
$postfix=array('walnut' => 0.16, 'chicken egg'=>0.35,
'grapefruit' => 1, 'bulgarian airbag' => 1.1,
'bulgarian funbag'=>3.27, 'football' => 11.07,
'olympic swim pool' => 4780114, 'known universe'=>1.17456E4933);
for the Vulture Central Weights and Measures Soviet volume standard.
without editing much of your code you can add additional if statement
test if the modular division by 1
yournumber%1
($i = floor(log($number, 10000)))), 0) % 1
gives you 0
if it doesnt then
multiply your number by 10 (you can make it a while statement so it multiplies it by 10 until there are no spaces after decimal point)
then return that number
so if you use your_number like 39.8 as an example it would look like this
while(your_number%1 != 0){
your_number*=10;
}
return your_number;
This a quick fix but its definitely not the best way to code this

PHP Question about bitwise

I have a script like this
$job = array(
1 => 'User',
2 => 'Editor',
4 => 'Supervisor',
8 => 'Manager',
10 => 'President');
$value = 18;
foreach($job as $key => $val)
{
if($value & $key)
{
$job[] = $key;
echo $val.', ';
}
}
now what I want to achieve is that in the example above '18' system must only display the value as ' Manager, President, ' ( 10+8 = 18; )
But if you run the script, the system displays as Editor, President,
that's not all the arrays I've got, I have like 23 more array values
Sorry but I really can't explain it in english, hope you understand...
<?php
$flags = array(
1 => 'User', // 00000001 Note the place of the 1
2 => 'Editor', // 00000010
4 => 'Supervisor', // 00000100
8 => 'Manager', // 00001000
16 => 'President' // 00010000
);
// permission we're going for
$permissions = 16 + 8; // 00011000 again, note the 1's places.
$levels = array();
foreach ($flags as $level => $name)
{
if (($permissions & $level) == $level)
$levels[] = $name;
}
echo implode(', ', $levels);
Output:
Manager, President
You want your values in powers of 2 so that, in binary, the corresponding flag matches the permission you're specifying.
The bit-wise AND (&) is saying (when it reaches Manager):
$flags $Pemissions $flags
if (00001000 & 00011000) == 00001000
if (00001000) == 00001000 [true]
Basically, if the flag is set on both sides (both the value you're checking for and against) keep that bit. Then, make sure it still equals the value you're checking for. If it does, the user is set to that permission. An AND is only true when both the left and the right values have the bit(s) set.
The value for President is wrong. To use a bitfield all numbers must be powers of two, so President should be 16 and not 10.
Note that 16 (decimal) is 0x10 (hex) -- perhaps setting the President value to 10 (decimal) was a copy/paste error?
Your problem is that 10 is not a 2^y variable.
10 = 2+8 (2^1 and 2^3), and thus will match values 2 and 8 respectively.
If you want to allow bitwise selection like you do; you need to pick 2^y values for your indexes (1, 2, 4, 8, 16, 32, etc).
Then you can safely add those values as selectors (e.g. 16+4 (20), 2+32(34) etc).
you should change 10 to 16 (1,2,4,8,16,32, ..) or you may cannot understand some number. Is 10=10 or 10=2+8

Categories